BZOJ-1001-[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)
道路上的权值表示这条路上最多能够通过的兔子数,道路是无向的. 左上角和右下角为兔子的两个窝,
开始时所有的兔子都聚集在左上角(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
HINT
2015.4.16新加数据一组,可能会卡掉从前可以过的程序。
题解
这道题一眼看到就觉得是网络流
也可以用最短路来做
这里介绍一下网络流的做法
我们可以把一对(x,y)转化成一个值(n和m都小于等于1000,所以(n,m)最大也就1,000,000)
加边,进行网络流
但是网络流我以前只会O(n^2*m) 的,看数据感觉要超时
后来发现当dfs找答案的时候可以优化一下(具体可以看一下我的上一篇博客)
所以这样时间复杂度立刻就降下来了
1 #include<bits/stdc++.h> 2 #define MAX 1e9 3 #define NM 1000005 4 using namespace std; 5 int n,m,val,tot,ans,dis; 6 int head[NM],level[NM],q[NM]; 7 struct node{ 8 int next,to,dis; 9 }E[6*NM]; 10 void add(int x,int y,int z){ 11 tot++; 12 E[tot].next=head[x]; 13 head[x]=tot; 14 E[tot].to=y; 15 E[tot].dis=z; 16 tot++; 17 E[tot].next=head[y]; 18 head[y]=tot; 19 E[tot].to=x; 20 E[tot].dis=z; 21 } 22 void pre(){ 23 for (int i=1;i<=n;i++) 24 for (int j=1;j<m;j++){ 25 scanf("%d",&val); 26 add((i-1)*m+j,(i-1)*m+j+1,val); 27 } 28 for (int i=1;i<n;i++) 29 for (int j=1;j<=m;j++){ 30 scanf("%d",&val); 31 add((i-1)*m+j,i*m+j,val); 32 } 33 for (int i=1;i<n;i++) 34 for (int j=1;j<m;j++){ 35 scanf("%d",&val); 36 add((i-1)*m+j,i*m+j+1,val); 37 } 38 } 39 bool bfs(){ 40 memset(level,0,sizeof(level)); 41 level[1]=1; 42 int t=1,w=1; 43 q[1]=1; 44 while (t<=w){ 45 int k=q[t]; 46 for (int i=head[k];i!=-1;i=E[i].next){ 47 int y=E[i].to; 48 if (E[i].dis&&!level[y]){ 49 level[y]=level[k]+1; 50 q[++w]=y; 51 } 52 } 53 t++; 54 } 55 return level[n*m]!=0; 56 } 57 int dfs(int s,int maxf){ 58 if (s==n*m) return maxf; 59 int ret=0; 60 for (int i=head[s];i!=-1;i=E[i].next){ 61 int y=E[i].to; 62 dis=E[i].dis; 63 if (dis&&level[s]+1==level[y]){ 64 int Min=min(maxf-ret,dis); 65 dis=dfs(y,Min); 66 E[i].dis-=dis; 67 E[i^1].dis+=dis; 68 ret+=dis; 69 if (ret==maxf) return ret; 70 } 71 } 72 if (!ret) level[s]=0; 73 return ret; 74 } 75 void Dinic(){ 76 ans=0; 77 while (bfs()) ans+=dfs(1,MAX); 78 printf("%d\n",ans); 79 } 80 int main(){ 81 scanf("%d%d",&n,&m); 82 memset(head,-1,sizeof(head)); 83 pre(); 84 Dinic(); 85 return 0; 86 }