Description
現在小朋友們最喜歡的"喜羊羊與灰太狼",話說灰太狼抓羊不到,但抓兔子還是比較在行的,
而且現在的兔子還比較笨,它們只有兩個窩,現在你做為狼王,面對下面這樣一個網格的地形:
左上角點為(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
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
正解:Dinic(裸網絡流)
解題報告:
大概題意是給一個網格圖,然后橫向、豎向、斜向都有邊相連,然后問圖的最小割
上網查滿地跑的對偶圖,然后學了一下對偶圖,但並不打算用轉對偶圖,盡管好像很簡單
於是試圖用Dicnic強上,直接把每條邊連進去,暴力網絡流。
就當網絡流練手題吧。
值得一提的是,需要用一些優化不然會TLE:當發現拓展到當前的結點發現可拓展流量為0,那么這個點在這下一次重新BFS建分層圖時顯然不會再用的上(畫個圖yy一下就可以了) 所以直接dis[now]=-1,相當於把它“堵塞”住了。
//It is made by jump~ #include <iostream> #include <cstdlib> #include <cstring> #include <cstdio> #include <cmath> #include <algorithm> #include <ctime> #include <vector> #include <queue> #include <map> #ifdef WIN32 #define OT "%I64d" #else #define OT "%lld" #endif using namespace std; typedef long long LL; const int MAXM = 6000011; const int MAXN = 1000011; int inf; int n,m; int first[MAXN]; int ecnt; int s,t; int dis[MAXN]; int ans; struct edge{ int v,f; int next; }e[MAXM]; inline int getint() { int w=0,q=0; char c=getchar(); while((c<'0' || c>'9') && c!='-') c=getchar(); if (c=='-') q=1, c=getchar(); while (c>='0' && c<='9') w=w*10+c-'0', c=getchar(); return q ? -w : w; } inline void link(int x,int y,int z){ e[++ecnt].next=first[x]; first[x]=ecnt; e[ecnt].v=y; e[ecnt].f=z; e[++ecnt].next=first[y]; first[y]=ecnt; e[ecnt].v=x; e[ecnt].f=z; } inline bool bfs(){ memset(dis,127/3,sizeof(dis)); int cun=dis[t]; queue<int>Q; while(!Q.empty()) Q.pop(); dis[1]=1; Q.push(1); while(!Q.empty()) { int u=Q.front(); Q.pop(); for(int i=first[u];i;i=e[i].next) { if(e[i].f && dis[e[i].v]==cun) { dis[e[i].v]=dis[u]+1; Q.push(e[i].v); } } if(dis[t]!=cun) return true; } return false; } inline int maxflow(int now,int remain){ if(remain==0 || now==t) return remain; int flow=0; for(int i=first[now];i;i=e[i].next){ if(dis[e[i].v]==dis[now]+1 && e[i].f){ int f=maxflow(e[i].v,min(remain,e[i].f)); if(f) { e[i].f-=f; e[i^1].f+=f; flow+=f; remain-=f; if(remain==0) return flow; } else dis[e[i].v]=-1; } } return flow; } inline void solve(){ s=1,t=n*m; inf=1; for(int i=1;i<=30;i++) inf*=2; while(bfs()) { ans+=maxflow(s,inf); } printf("%d",ans); } int main() { n=getint(); m=getint(); int x; ecnt=1; int nowx,nownex; for(int i=1;i<=n;i++) for(int j=1;j<m;j++){ nowx=(i-1)*m+j,nownex=nowx+1; x=getint(); link(nowx,nownex,x); } for(int i=1;i<n;i++) for(int j=1;j<=m;j++) { nowx=(i-1)*m+j,nownex=nowx+m; x=getint(); link(nowx,nownex,x); } for(int i=1;i<n;i++) for(int j=1;j<m;j++) { nowx=(i-1)*m+j,nownex=nowx+m+1; x=getint(); link(nowx,nownex,x); } solve(); return 0; }