[bzoj1001][BeiJing2006]狼抓兔子-题解[平面图最小割转最短路]/[Dinic求最小割]
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[bzoj1001][BeiJing2006]狼抓兔子-题解[平面图最小割转最短路]/[Dinic求最小割]相关的知识,希望对你有一定的参考价值。
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做的,而且跑的挺快,也可以用平面图最小割转最短路。
我觉得会Dinic的也稍微看看这个东西吧,多了解一点东西总是好的 。
这个平面图最小割转最短路不了解的可以去看周冬的论文。
将平面图转成对偶图以后求最短路就行了。
如果没看懂的话可以暂且看看我这里的解释。。(但务必要看!)
在你构造对偶图的时候,你会发现,你不知道外面的那个面属于源点还是汇点。
就像这张图,我们把每一条边都构造出与其对偶的一条边,作一条源点到汇点的对角线(这条线并不是一条边),然后将整个对偶图分为两面,一面作为源点,另一面为汇点。
每一条边相当于拦截原图的一条对应边,因此从对偶图源点到汇点的一条路径就对应一条割。
所以我们使每一条对偶图的边的权值都等于对应边的权值,这样得到的最短路就是最小割了。
啊。。就是这样啦。。接下来上代码。。(我最短路写的很丑。。)
1 #include<iostream> 2 #include<cstdio> 3 #include<cstdlib> 4 #include<cstring> 5 #include<queue> 6 #define N 1000 7 #define M 1000 8 #define mod N*M 9 #define Max 2147483647 10 #define ll long long 11 #define l(A,B) ((A-1)*m+B) 12 using namespace std; 13 struct edge 14 { 15 int to; 16 int next; 17 int dis; 18 }mp[((N-1)*M+(M-1)*N+(N-1)*(M-1))*2]; 19 int n,m,h,head[N*M+5],que[N*M+5],tip,hd,tl,ans,s,t; 20 ll tim=1,user[N*M+5]; 21 int read() 22 { 23 char ch=getchar();int kin=1,gi=0; 24 while(ch>‘9‘||ch<‘0‘){if(ch==‘-‘)kin=-1;ch=getchar();} 25 while(ch>=‘0‘&&ch<=‘9‘){gi=gi*10+ch-48;ch=getchar();} 26 return kin*gi; 27 } 28 void add(int u,int v,int dis) 29 { 30 mp[++h].dis=dis; 31 mp[h].to=v; 32 mp[h].next=head[u]; 33 head[u]=h; 34 } 35 void init() 36 { 37 int k; 38 for(int i=1;i<=n;++i) 39 for(int j=1;j<m;++j) 40 { 41 k=read(); 42 add(l(i,j),l(i,j+1),k); 43 add(l(i,j+1),l(i,j),k); 44 } 45 for(int i=1;i<n;++i) 46 for(int j=1;j<=m;++j) 47 { 48 k=read(); 49 add(l(i,j),l(i+1,j),k); 50 add(l(i+1,j),l(i,j),k); 51 } 52 for(int i=1;i<n;++i) 53 for(int j=1;j<m;++j) 54 { 55 k=read(); 56 add(l(i,j),l(i+1,j+1),k); 57 add(l(i+1,j+1),l(i,j),k); 58 } 59 } 60 int bfs() 61 { 62 int nw; 63 tl=0;hd=0; 64 tip=user[s]=tim;que[tl++]=s;tl%=mod; 65 while(tl!=hd) 66 { 67 nw=que[hd++];hd%=mod; 68 for(int i=head[nw];i;i=mp[i].next) 69 { 70 if(user[mp[i].to]<tim&&mp[i].dis>0) 71 { 72 user[mp[i].to]=user[nw]+1; 73 if(user[mp[i].to]>tip)tip=user[mp[i].to]; 74 que[tl++]=mp[i].to;tl%=mod; 75 if(mp[i].to==t)return 1; 76 } 77 } 78 } 79 return 0; 80 } 81 int dinic(int x,int y) 82 { 83 if(x==t)return y; 84 int l=y,travel; 85 for(int i=head[x];i;i=mp[i].next) 86 { 87 if(user[mp[i].to]==user[x]+1&&mp[i].dis>0) 88 { 89 travel=dinic(mp[i].to,min(mp[i].dis,y)); 90 y-=travel; 91 mp[i].dis-=travel; 92 mp[((i-1)^1)+1].dis+=travel; 93 if(!y)break; 94 } 95 } 96 if(y==l)user[x]=0; 97 return l-y; 98 } 99 void work() 100 { 101 while(bfs()) 102 { 103 tim=tip+1; 104 ans+=dinic(s,Max); 105 } 106 } 107 int main() 108 { 109 n=read();m=read(); 110 s=1;t=l(n,m); 111 init(); 112 work(); 113 printf("%d\\n",ans); 114 return 0; 115 }
1 #include<iostream> 2 #include<cstdio> 3 #include<cstdlib> 4 #include<cstring> 5 #include<queue> 6 #define Max 2147483640 7 #define dis first 8 #define pos second 9 #define mk(A,B) make_pair(A,B) 10 #define d(A,B,C) ((A-1)*m*2+m*(C-1)+B) 11 using namespace std; 12 typedef pair<int,int> nod; 13 int read() 14 { 15 char ch=getchar();int cn=0,kin=1; 16 while(ch>‘9‘||ch<‘0‘){if(ch==‘-‘)kin=-1;ch=getchar();} 17 while(ch>=‘0‘&&ch<=‘9‘){cn=cn*10+ch-48;ch=getchar();} 18 return cn*kin; 19 } 20 struct ni 21 { 22 vector<int>s[2]; 23 int ml; 24 }a[2000005]; 25 int n,m,t; 26 priority_queue<nod,vector<nod>,greater<nod> >que; 27 void get(int,int); 28 void init(); 29 int main() 30 { 31 freopen("a.in","r",stdin); 32 n=read()-1;m=read()-1; 33 if(n==0||m==0) 34 { 35 36 if(n<m)swap(n,m); 37 int la,ans=Max; 38 for(int i=1;i<=n;++i) 39 { 40 la=read(); 41 ans=min(ans,la); 42 } 43 cout<<ans<<endl;return 0; 44 } 45 t=n*2*m+1; 46 init();que.push(mk(0,0)); 47 int nw,d; 48 while(!que.empty()) 49 { 50 nw=que.top().second;d=que.top().first;que.pop(); 51 for(int i=0;i<a[nw].s[0].size();++i) 52 { 53 if(d+a[nw].s[1][i]<a[a[nw].s[0][i]].ml) 54 { 55 a[a[nw].s[0][i]].ml=d+a[nw].s[1][i]; 56 que.push(mk(a[a[nw].s[0][i]].ml,a[nw].s[0][i])); 57 } 58 } 59 } 60 cout<<a[t].ml<<endl; 61 fclose(stdin); 62 return 0; 63 } 64 void get(int x,int y) 65 { 66 int t1; 67 t1=read(); 68 a[x].s[0].push_back(y); 69 a[x].s[1].push_back(t1); 70 a[y].s[0].push_back(x); 71 a[y].s[1].push_back(t1); 72 } 73 void init() 74 { 75 for(int i=1;i<=n*2*m;++i) 76 { 77 a[i].ml=Max; 78 }a[t].ml=Max; 79 for(int i=1;i<=n+1;++i) 80 for(int j=1;j<=m;++j) 81 { 82 if(i==1) 83 get(d(i,j,1),t); 84 else if(i==n+1) 85 get(0,d(i-1,j,2)); 86 else 87 get(d(i,j,1),d(i-1,j,2)); 88 } 89 for(int i=1;i<=n;++i) 90 for(int j=1;j<=m+1;++j) 91 { 92 if(j==1) 93 get(d(i,j,2),0); 94 else if(j==m+1) 95 get(d(i,j-1,1),t); 96 else 97 get(d(i,j,2),d(i,j-1,1)); 98 } 99 for(int i=1;i<=n;++i) 100 for(int j=1;j<=m;++j) 101 { 102 get(d(i,j,1),d(i,j,2)); 103 } 104 }
以上是关于[bzoj1001][BeiJing2006]狼抓兔子-题解[平面图最小割转最短路]/[Dinic求最小割]的主要内容,如果未能解决你的问题,请参考以下文章