[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

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求最小割]的主要内容,如果未能解决你的问题,请参考以下文章

bzoj1001 [BeiJing2006]狼抓兔子

bzoj1001 [BeiJing2006]狼抓兔子

BZOJ1001 [BeiJing2006]狼抓兔子

[BZOJ1001][BeiJing2006]狼抓兔子

BZOJ1001: [BeiJing2006]狼抓兔子

BZOJ 1001: [BeiJing2006]狼抓兔子