首页 > 代码库 > [bzoj1001][BeiJing2006]狼抓兔子-题解[平面图最小割转最短路]/[Dinic求最小割]

[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

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 }
Dinic
技术分享
  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求最小割]