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

最短路

时间: 2024-10-02 16:39:55

[bzoj1001][BeiJing2006]狼抓兔子-题解[平面图最小割转最短路]/[Dinic求最小割]的相关文章

bzoj1001 [BeiJing2006]狼抓兔子

1001: [BeiJing2006]狼抓兔子 Time Limit: 15 Sec  Memory Limit: 162 MBSubmit: 23723  Solved: 5981[Submit][Status][Discuss] Description 现在小朋友们最喜欢的"喜羊羊与灰太狼",话说灰太狼抓羊不到,但抓兔子还是比较在行的, 而且现在的兔子还比较笨,它们只有两个窝,现在你做为狼王,面对下面这样一个网格的地形: 左上角点为(1,1),右下角点为(N,M)(上图中N=4,M

BZOJ1001: [BeiJing2006]狼抓兔子【最短路】

题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=1001 1001: [BeiJing2006]狼抓兔子 Time Limit: 15 Sec  Memory Limit: 162 MBSubmit: 27684  Solved: 7127 Description 现在小朋友们最喜欢的"喜羊羊与灰太狼",话说灰太狼抓羊不到,但抓兔子还是比较在行的, 而且现在的兔子还比较笨,它们只有两个窝,现在你做为狼王,面对下面这样一个网格的

BZOJ1001[BeiJing2006]狼抓兔子(无向图最小割)

传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=1001 这题的题意其实就是求一个最小割,但是由于是无向图,所以加边的时候,两边的流量都要是输入的权值,然后就是一个dinic求一下最小割. 但是这题貌似有很高超的技巧来搞,可以把平面图上的最小割转成对偶图上的最短路来做,这样可以起到很明显的优化效果.现在还不是很明白,如果以后明白了,会再来更新. dinic: #include <cstdio> #include <cstring&g

[BZOJ1001] [Beijing2006] 狼抓兔子 (最短路)

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) 道路上的权值表示这条路上最多能够通过的兔子数,道路是

_bzoj1001 [BeiJing2006]狼抓兔子【平面图】

传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=1001 顺便推荐一个ppt,里面有对平面图的介绍:浅析最大最小定理在信息学竞赛中的应用. 这里直接求最小割肯定会T,所以应把原图看成一张平面图,ppt中说该平面图对应的对偶图的每一个环对应原图的一个割,这点有些不理解,不过不影响做这一道题.想象一下,在最外面那个无限大的平面,由左上角朝右下角连一条附加的边,这么做就多了一个附加面,设这条附加的边的权值为 -inf,那么最小割一定包含这一条边.

【平面图】【最小割】【最短路】【Heap-Dijkstra】bzoj1001 [BeiJing2006]狼抓兔子

http://wenku.baidu.com/view/8f1fde586edb6f1aff001f7d.html #include<cstdio> #include<queue> #include<cstring> using namespace std; typedef long long ll; #define N 1001 int n,m,S,T,nn; struct Point{int u,d;}; bool operator < (Point a,Po

BZOJ1001: [BeiJing2006]狼抓兔子 (最小割转最短路)

浅析最大最小定理在信息学竞赛中的应用---周东 ↑方法介绍 对于一个联通的平面图G(满足欧拉公式) 在s和t间新连一条边e; 然后建立一个原图的对偶图G*,G*中每一个点对应原图中每一个面,每一条边对应分割面的每一条边; 那么对偶图G*中,以原图s和t间边e新划分出的面作为起点(s*),最外的面作为终点(t*); 那么从s*到t*的每一条路都是原图G的一个割; 下图来自上方标出百度文库网址的ppt; 然后用堆(优先队列)优化的迪杰斯特拉,复杂度 O((m+n)logn) n为点数,m为边数...

BZOJ 1001: [BeiJing2006]狼抓兔子【最大流/SPFA+最小割,多解】

1001: [BeiJing2006]狼抓兔子 Time Limit: 15 Sec  Memory Limit: 162 MBSubmit: 23822  Solved: 6012[Submit][Status][Discuss] Description 现在小朋友们最喜欢的"喜羊羊与灰太狼",话说灰太狼抓羊不到,但抓兔子还是比较在行的, 而且现在的兔子还比较笨,它们只有两个窝,现在你做为狼王,面对下面这样一个网格的地形: 左上角点为(1,1),右下角点为(N,M)(上图中N=4,M

BZOJ_2001_[BeiJing2006]狼抓兔子_最小割转对偶图

BZOJ_2001_[BeiJing2006]狼抓兔子 题意:http://www.lydsy.com/JudgeOnline/problem.php?id=1001 分析:思路同NOI2010海拔. 注意无向图. 代码: 1 #include <stdio.h> 2 #include <string.h> 3 #include <algorithm> 4 #include <queue> 5 using namespace std; 6 #define S