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; }