BZOJ_1001_狼抓兔子_(平面图求最小割+对偶图求最短路)
描述
http://www.lydsy.com/JudgeOnline/problem.php?id=1001
1001: [BeiJing2006]狼抓兔子
Time Limit: 15 Sec Memory Limit: 162 MBSubmit: 17068 Solved: 4171
[Submit][Status][Discuss]
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新加数据一组,可能会卡掉从前可以过的程序。
Source
分析
平面图求最小割,转化成对偶图求最短路,经典.
注意:
1.优先队列是个大根堆.
2.Dijkstra可以带一个vis数组,也可以不带,因为一个点出来以后,它更新的的点和原本就在队列里的点都比它大,所以它不可能被更新得更小,之后这个点再出队时情况不比第一次更优,所以出队也不会有操作.
3.双向边,数组要开够(貌似不是第一次犯这个错误).
4.网上有人说m==1||n==1的情况可以不特判,在get函数中已经可以处理妥当,大丈夫.
1 #include <cstdio> 2 #include <queue> 3 #include <algorithm> 4 using namespace std; 5 6 const int maxn=1000+10,oo=1<<27; 7 int n,m,cnt; 8 int d[maxn*maxn*2],head[maxn*maxn*4]; 9 bool vis[maxn*maxn*2]; 10 struct edge{ 11 int to,w,next; 12 edge(){} 13 edge(int a,int b,int c):to(a),w(b),next(c){} 14 bool operator<(const edge &a) const { return a.w<w; } 15 }g[maxn*maxn*6]; 16 void insert(int from,int to,int w){ 17 g[++cnt]=edge(to,w,head[from]); head[from]=cnt; 18 g[++cnt]=edge(from,w,head[to]); head[to]=cnt; 19 } 20 21 int get(int x,int y,int z){ 22 if(x<1||y>=m) return ((n-1)*(m-1)<<1)+1; 23 if(x>=n||y<1) return 0; 24 return (((x-1)*(m-1)+y-1)<<1)+z+1; 25 } 26 int Dijkstra(int s,int t){ 27 for(int i=0;i<=((n-1)*(m-1)<<1)+1;i++) d[i]=oo; 28 d[s]=0; 29 priority_queue <edge> q; 30 q.push(edge(s,0,0)); 31 while(!q.empty()){ 32 edge e=q.top(); q.pop(); 33 int x=e.to; 34 if(vis[x]) continue; 35 vis[x]=true; 36 for(int i=head[x];i;i=g[i].next){ 37 int y=g[i].to; 38 if(d[y]>d[x]+g[i].w){ 39 d[y]=d[x]+g[i].w; 40 q.push(edge(y,d[y],0)); 41 } 42 } 43 } 44 return d[t]; 45 } 46 47 void init(){ 48 for(int i=1;i<=n;i++){ 49 for(int j=1;j<m;j++){ 50 int a; scanf("%d",&a); 51 insert(get(i,j,1),get(i-1,j,0),a); 52 } 53 } 54 for(int i=1;i<n;i++){ 55 for(int j=1;j<=m;j++){ 56 int a; scanf("%d",&a); 57 insert(get(i,j-1,1),get(i,j,0),a); 58 } 59 } 60 for(int i=1;i<n;i++){ 61 for(int j=1;j<m;j++){ 62 int a; scanf("%d",&a); 63 insert(get(i,j,0),get(i,j,1),a); 64 } 65 } 66 } 67 68 int main(){ 69 scanf("%d%d",&n,&m); 70 init(); 71 printf("%d\n",Dijkstra(0,((n-1)*(m-1)<<1)+1)); 72 return 0; 73 }