【BZOJ - 1001】狼抓兔子(无向图网络流,最小割,或平面图转对偶图求最短路SPFA)
題干:
現在小朋友們最喜歡的"喜羊羊與灰太狼",話說灰太狼抓羊不到,但抓兔子還是比較在行的,
而且現在的兔子還比較笨,它們只有兩個窩,現在你做為狼王,面對下面這樣一個網格的地形:
?
左上角點為(1,1),右下角點為(N,M)(上圖中N=4,M=5).有以下三種類型的道路?
1:(x,y)<==>(x+1,y)?
2:(x,y)<==>(x,y+1)?
3:(x,y)<==>(x+1,y+1)?
道路上的權值表示這條路上最多能夠通過的兔子數,道路是無向的. 左上角和右下角為兔子的兩個窩,
開始時所有的兔子都聚集在左上角(1,1)的窩里,現在它們要跑到右下解(N,M)的窩中去,狼王開始伏擊
這些兔子.當然為了保險起見,如果一條道路上最多通過的兔子數為K,狼王需要安排同樣數量的K只狼,
才能完全封鎖這條道路,你需要幫助狼王安排一個伏擊方案,使得在將兔子一網打盡的前提下,參與的
狼的數量要最小。因為狼還要去找喜羊羊麻煩.
Input
第一行為N,M.表示網格的大小,N,M均小于等于1000.
接下來分三部分
第一部分共N行,每行M-1個數,表示橫向道路的權值.?
第二部分共N-1行,每行M個數,表示縱向道路的權值.?
第三部分共N-1行,每行M-1個數,表示斜向道路的權值.?
輸入文件保證不超過10M
Output
輸出一個整數,表示參與伏擊的狼的最小數量.
Sample Input
3 4 5 6 4 4 3 1 7 5 3 5 6 7 8 8 7 6 5 5 5 5 6 6 6
Sample Output
14
Hint
?
?2015.4.16新加數據一組,可能會卡掉從前可以過的程序。
?
解題報告:
? ?首先題干有誤,這顯然是不對的、、、不過還好樣例是正確的。。
然后,對于無向圖求最小割,加反邊直接把板子的反邊流量0也改成w就可以了。
AC代碼:
#include<cstdio> #include<iostream> #include<algorithm> #include<queue> #include<map> #include<vector> #include<set> #include<string> #include<cmath> #include<cstring> #define ll long long using namespace std; const int MAXN = 1005000; const int MAXM = 6005000; const int INF = 0x3f3f3f3f; struct Edge {int to,next,cap,flow; } edge[MAXM]; int tol; int head[MAXN]; void init() {tol = 2;memset(head, -1,sizeof(head)); } void addedge(int u,int v,int w,int rw = 0) {edge[tol].to = v;edge[tol].cap = w;edge[tol].flow = 0;edge[tol].next = head[u];head[u] = tol++;edge[tol].to = u;edge[tol].cap = rw;edge[tol].flow = 0;edge[tol].next = head[v];head[v] = tol++; } int Q[MAXN]; int dep[MAXN],cur[MAXN],sta[MAXN]; bool bfs(int s,int t,int n) {int front = 0,tail = 0;memset(dep,-1,sizeof(dep[0])*(n+1));dep[s] = 0;Q[tail++] = s;while(front < tail) {int u = Q[front++];for(int i = head[u]; i != -1; i = edge[i].next) {int v = edge[i].to;if(edge[i].cap > edge[i].flow && dep[v] == -1) {dep[v] = dep[u] + 1;if(v == t)return true;Q[tail++] = v;}}}return false; } int dinic(int s,int t,int n) {int maxflow = 0;while(bfs(s,t,n)) {for(int i = 1; i <= n; i++)cur[i] = head[i];int u = s, tail = 0;while(cur[s] != -1) {if(u == t) {int tp = INF;for(int i = tail-1; i >= 0; i-- )tp = min(tp,edge[sta[i]].cap - edge[sta[i]].flow);maxflow += tp;for(int i = tail-1; i >= 0; i-- ) {edge[sta[i]].flow += tp;edge[sta[i]^1].flow -= tp;if(edge[sta[i]].cap - edge[sta[i]].flow == 0)tail = i;}u = edge[sta[tail]^1].to;} else if(cur[u] != -1 && edge[cur[u]].cap > edge[cur[u]].flow && dep[u] + 1 == dep[edge[cur[u]].to]) {sta[tail++] = cur[u];u = edge[cur[u]].to;} else {while(u != s && cur[u] == - 1)u = edge[sta[--tail]^1].to;cur[u] = edge[cur[u]].next;}}}return maxflow; } int n,m; int id(int i,int j) {return (i-1)*m+j; } int main() {while(~scanf("%d%d",&n,&m)) {init();int st=1,ed=n*m;for(int w,i = 1; i<=n; i++) {for(int j = 1; j<=m-1; j++) {scanf("%d",&w);addedge(id(i,j),id(i,j+1),w,w);}}for(int w,i = 1; i<=n-1; i++) {for(int j = 1; j<=m; j++) {scanf("%d",&w);addedge(id(i,j),id(i+1,j),w,w);}}for(int w,i = 1; i<=n-1; i++) {for(int j = 1; j<=m-1; j++) {scanf("%d",&w);addedge(id(i,j),id(i+1,j+1),w,w);}}printf("%d\n",dinic(st,ed,n*m));} return 0 ; }這題還可以強行轉化成最短路問題:
https://www.cnblogs.com/reddest/p/5954756.html
也就是把他看成一個平面圖然后轉化成對偶圖,這樣轉化成一個最短路問題,但是建圖還是有一定難度。具體參考博客。
創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎總結
以上是生活随笔為你收集整理的【BZOJ - 1001】狼抓兔子(无向图网络流,最小割,或平面图转对偶图求最短路SPFA)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 《深海迷航冰点之下》控制台代码一览
- 下一篇: 【蓝桥杯官网试题 - 历届试题】格子刷