BZOJ_1001_狼抓兔子_(平面图求最小割+对偶图求最短路)

描述


http://www.lydsy.com/JudgeOnline/problem.php?id=1001

 

 

1001: [BeiJing2006]狼抓兔子

Time Limit: 15 Sec  Memory Limit: 162 MB
Submit: 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

 

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 }
View Code

 

 

 

 

posted @ 2016-05-13 21:51  晴歌。  阅读(310)  评论(0编辑  收藏  举报