【BZOJ1001】狼抓兔子
1001: [BeiJing2006]狼抓兔子
Time Limit: 15 Sec Memory Limit: 162 MBSubmit: 7530 Solved: 1724
[Submit][Status]
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
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
HINT
Source
分析:根据题意很容易想到是(1,1)到(n,m)最大流,但最多会有10^6点,普通的会TLE。本屌丝当然也没招~~搜了题解,原来是2008周冬的集训队论文里提到的平面图的最大流——>最小割——>对偶图的最短路,于是可以最短路做,我用的是dijkstra+heap
题解:关于平面图的最大流详见周冬的论文(AH的oier呢好骄傲~~~),这里我只想提一下,根据平面图的定义,几乎所有最大流问题都可以这样做,当然前提是容易判断各个面,目前我见到的只是这种网格网络流,求大神分享其他的……
然后这题只剩建图了:大家自己在草稿纸画画就行了,我是将s点定为0,t点定为(n-1)*(m-1)*2+1(因为里面有(n-1)*(m-1)*2的三角形面),然后就是按顺序给里面的三角形编号,从左到右从上到下编号。然后有左边界或者下边界的连向s,有上边界或者右边界的连向t,中间的处理画画图谢谢式子就行了,具体看我程序
注意:1、建图的时候左下角会连2次s,右上角会连2次t,所以要判重,取两条边中最小的
2、特判m=1或n=1,ans是输入的数中的最小值
1 #include<cstdio> 2 #include<algorithm> 3 #include<queue> 4 #include<cstring> 5 #include<vector> 6 using namespace std; 7 const int maxn=1000; 8 const int maxm=1000; 9 const int inf=1000000000; 10 struct heap 11 { 12 int d,u; 13 bool operator < (const heap& x) const 14 { 15 return d>x.d; 16 } 17 }; 18 priority_queue<heap> q; 19 struct wjmzbmr 20 { 21 int to,data; 22 }; 23 vector<wjmzbmr> g[(maxn-1)*(maxm-1)*2+50]; 24 int n,m,d[(maxn-1)*(maxm-1)*2+50],f[(maxn-1)*(maxm-1)*2+50]; 25 void ins(int a,int b,int w) 26 { 27 g[a].push_back({b,w}); 28 g[b].push_back({a,w}); 29 } 30 int main() 31 { scanf("%d%d",&n,&m); 32 for(int i=0;i<=(maxn-1)*(maxm-1)*2+1;++i) g[i].clear(); 33 if(n==1&&m==1) 34 { 35 printf("0"); 36 return 0; 37 } 38 if(n==1) 39 { 40 int s=inf,x; 41 for(int i=1;i<m;++i) scanf("%d",&x),s=min(s,x); 42 printf("%d",s); 43 return 0; 44 } 45 if(m==1) 46 { 47 int s=inf,x; 48 for(int i=1;i<n;++i) scanf("%d",&x),s=min(s,x); 49 printf("%d",s); 50 return 0; 51 } 52 int s=0,t=(n-1)*(m-1)*2+1,a=inf,b=inf; 53 for(int i=1;i<=n;++i) 54 for(int j=1;j<m;++j) 55 { 56 int x; 57 scanf("%d",&x); 58 if(i==1&&j==m-1) 59 { 60 a=min(x,a); 61 continue; 62 } 63 if(i==n&&j==1) 64 { 65 b=min(x,b); 66 continue; 67 } 68 if(i==1) ins(j,t,x); 69 if(i==n) ins((n-2)*(m-1)*2+m-1+j,s,x); 70 if(i!=1&&i!=n) ins(2*(i-2)*(m-1)+m-1+j,2*(i-1)*(m-1)+j,x); 71 72 } 73 for(int i=1;i<=n-1;++i) 74 for(int j=1;j<=m;++j) 75 { 76 int x; 77 scanf("%d",&x); 78 if(i==1&&j==m) 79 { 80 a=min(x,a); 81 continue; 82 } 83 if(i==n-1&&j==1) 84 { 85 b=min(x,b); 86 continue; 87 } 88 if(j==1) ins(s,(i-1)*2*(m-1)+m,x); 89 if(j==m) ins(t,(i-1)*2*(m-1)+m-1,x); 90 if(j!=1&&j!=m) ins((i-1)*2*(m-1)+j-1,(i-1)*2*(m-1)+m-1+j,x); 91 } 92 for(int i=1;i<=n-1;++i) 93 for(int j=1;j<=m-1;++j) 94 { 95 int x; 96 scanf("%d",&x); 97 ins((i-1)*2*(m-1)+j,(i-1)*(m-1)*2+m-1+j,x); 98 } 99 ins(m-1,t,a);ins(t-m+1,0,b); 100 memset(f,0,sizeof(f)); 101 for(int i=s;i<=t;++i) d[i]=inf;d[s]=0; 102 while(!q.empty())q.pop(); 103 q.push({0,s}); 104 while(!q.empty()) 105 { 106 heap x=q.top();q.pop(); 107 if(f[x.u]==1) continue; 108 f[x.u]=1; 109 for(int i=0;i<g[x.u].size();++i) 110 if(d[x.u]+g[x.u][i].data<d[g[x.u][i].to]) 111 { 112 d[g[x.u][i].to]=d[x.u]+g[x.u][i].data; 113 q.push({d[g[x.u][i].to],g[x.u][i].to}); 114 } 115 } 116 printf("%d",d[t]); 117 return 0; 118 }