1. 程式人生 > >BZOJ1001 [BeiJing2006]狼抓兔子 平面圖轉對偶圖,最小割轉最短路

BZOJ1001 [BeiJing2006]狼抓兔子 平面圖轉對偶圖,最小割轉最短路

bits ges code inf 如果 對偶圖 += ron oid

1001: [BeiJing2006]狼抓兔子

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

很容易可以看出這是一道求最小割的題,但圖太大了網絡流沒法跑。網上有人網絡流水過的,但我寫的網絡流莫名奇妙一直WA...

技術分享圖片
  1 /**************************************************************
  2     Problem: 1001
  3     User: mizersy
  4     Language: C++
  5     Result: Wrong_Answer
  6 ****************************************************************/
  7  
  8 #include <bits/stdc++.h>
  9 using namespace
std; 10 const int MAXN = 2000010; 11 const int MAXM = 6200010; 12 const int INF = 0x3f3f3f3f; 13 struct Edge{ 14 int to,next,cap,flow; 15 } edge[MAXM]; 16 int tol; 17 int head[MAXN]; 18 void init(){ 19 tol = 2; 20 memset(head,-1,sizeof(head)); 21 } 22 void addedge(int u,int v,int w,int rw = 0){ 23 edge[tol].to = v; 24 edge[tol].cap = w; 25 edge[tol].flow = 0; 26 edge[tol].next = head[u]; 27 head[u] = tol++; 28 edge[tol].to = u; 29 edge[tol].cap = rw; 30 edge[tol].flow = 0; 31 edge[tol].next = head[v]; 32 head[v] = tol++; 33 } 34 int Q[MAXN]; 35 int dep[MAXN],cur[MAXN],sta[MAXN]; 36 bool bfs(int s,int t,int n){ 37 int front = 0,tail = 0; 38 memset(dep,-1,sizeof(dep[0])*(n+1)); 39 dep[s] = 0; 40 Q[tail++] = s; 41 while(front < tail){ 42 int u = Q[front++]; 43 for(int i = head[u]; i !=-1; i = edge[i].next){ 44 int v = edge[i].to; 45 if(edge[i].cap > edge[i].flow && dep[v] ==-1){ 46 dep[v] = dep[u] + 1; 47 if(v == t) 48 return true; 49 Q[tail++] = v; 50 } 51 } 52 } 53 return false; 54 } 55 int dinic(int s,int t,int n){ 56 int maxflow = 0; 57 while(bfs(s,t,n)){ 58 for(int i = 0; i <= n; i++) cur[i] = head[i]; 59 int u = s, tail = 0; 60 while(cur[s] !=-1){ 61 if(u == t){ 62 int tp = INF; 63 for(int i = tail-1; i >= 0; i--) 64 tp = min(tp,edge[sta[i]].cap-edge[sta[i]].flow); 65 maxflow += tp; 66 for(int i = tail-1; i >= 0; i--){ 67 edge[sta[i]].flow += tp; 68 edge[sta[i]^1].flow-= tp; 69 if(edge[sta[i]].cap-edge[sta[i]].flow == 0) 70 tail = i; 71 } 72 u = edge[sta[tail]^1].to; 73 }else if(cur[u] !=-1 && edge[cur[u]].cap > edge[cur[u]].flow && dep[u] + 1 == dep[edge[cur[u]].to]) 74 { 75 sta[tail++] = cur[u]; 76 u = edge[cur[u]].to; 77 }else{ 78 while(u != s && cur[u] ==-1) 79 u = edge[sta[--tail]^1].to; 80 cur[u] = edge[cur[u]].next; 81 } 82 } 83 } 84 return maxflow; 85 } 86 int n,m,cnt; 87 int a[1005][1005]; 88 89 int point(int i,int j){ 90 return (i-1)*m+j; 91 } 92 93 int main(){ 94 scanf("%d%d",&n,&m); 95 cnt = 0; 96 init(); 97 memset(a,0,sizeof(a)); 98 for (int i = 1;i <= n;++i){ 99 for (int j = 1;j < m;++j){ 100 int w; scanf("%d",&w); 101 addedge(point(i,j),point(i,j+1),w); 102 } 103 } 104 for (int i = 1;i < n;++i){ 105 for (int j = 1;j <= m;++j){ 106 int w; scanf("%d",&w); 107 addedge(point(i,j),point(i+1,j),w); 108 } 109 } 110 for (int i = 1;i < n;++i){ 111 for (int j = 1;j < m;++j){ 112 int w; scanf("%d",&w); 113 addedge(point(i,j),point(i+1,j+1),w); 114 } 115 } 116 printf("%d\n",dinic(1,n*m,n*m)); 117 }
View Code

查了題解說因為圖是平面圖,所以可以把平面圖轉對偶圖,然後對偶圖的最短路就是平面圖的最小割,驚了。 上學期離散課上學過平面圖轉對偶圖,但是課時比較趕老師就講的很水,當時沒覺得這東西有什麽用然後就沒深入研究 想不到轉對偶圖居然還有這種妙用,不過想一下也很容易理解

對偶圖建圖的時候需要小心一點,寫的時候調了半天..

  1 /**************************************************************
  2     Problem: 1001
  3     User: mizersy
  4     Language: C++
  5     Result: Accepted
  6     Time:3108 ms
  7     Memory:118480 kb
  8 ****************************************************************/
  9  
 10 #include <bits/stdc++.h>
 11 using namespace std;
 12 const int MAXN = 2000005;
 13 struct Edge{int to,next,w;}edge[MAXN*4];
 14 int tol,n,m,w;
 15 int head[MAXN],vis[MAXN],dis[MAXN];
 16 void init(){
 17     tol = 0;
 18     memset(vis,0,sizeof(vis));
 19     memset(dis,0x3f3f3f3f,sizeof(dis));
 20     memset(head,-1,sizeof(head));
 21 }
 22  
 23 void addedge(int u,int v,int w){
 24     edge[tol] = Edge{v,head[u],w};
 25     head[u] = tol++;
 26     edge[tol] = Edge{u,head[v],w};
 27     head[v] = tol++;
 28 }
 29  
 30 void getmap(){
 31     for (int j = 1;j < m;++j){
 32         scanf("%d",&w);
 33         addedge(0,j*2,w);
 34     }
 35     for (int i = 2;i < n;++i){
 36         for (int j = 1;j < m;++j){
 37             scanf("%d",&w);
 38             addedge(2*(i-2)*(m-1)+j*2-1,2*(i-1)*(m-1)+j*2,w);
 39         }
 40     }
 41     if (n >= 2)
 42     for (int j = 1;j < m;++j){
 43         scanf("%d",&w);
 44         addedge(2*(n-2)*(m-1)+j*2-1,2*(n-1)*(m-1)+1,w);
 45     }
 46     for (int i = 1;i < n;++i){
 47         for (int j = 1;j <= m;++j){
 48             scanf("%d",&w);
 49             if (j == 1) addedge(2*(n-1)*(m-1)+1,2*(i-1)*(m-1)+1,w);
 50             else if (j == m) addedge(2*i*(m-1),0,w);
 51             else addedge(2*(i-1)*(m-1)+(j-1)*2,2*(i-1)*(m-1)+(j-1)*2+1,w);
 52         }
 53     }
 54  
 55     for (int i = 1;i < n;++i){
 56         for (int j = 1;j < m;++j){
 57             scanf("%d",&w);
 58             addedge(2*(i-1)*(m-1)+(j-1)*2+1,2*(i-1)*(m-1)+j*2,w);
 59         }
 60     }
 61 }
 62  
 63 int spfa(int s,int t){
 64     queue <int> q;
 65     dis[s] = 0; vis[s] = 1;
 66     q.push(s);
 67     while(!q.empty()){
 68         int u = q.front(); q.pop();
 69         vis[u] = 0;
 70         for (int i = head[u];i != -1;i = edge[i].next){
 71             int v = edge[i].to,w = edge[i].w;
 72             if (dis[v] > dis[u] + w){
 73                 dis[v] = dis[u] + w;
 74                 if (!vis[v]){
 75                     vis[v] = 1;
 76                     q.push(v);
 77                 }
 78             }
 79         }
 80     }
 81     return dis[t];
 82 }
 83  
 84 int main(){
 85     init();
 86     scanf("%d%d",&n,&m);
 87     if (n == 1 || m == 1){
 88         if (n > m) swap(n,m);
 89         int ans = 0x3f3f3f3f;
 90         for (int i = 1;i < m;++i){
 91             scanf("%d",&w);
 92             ans = min(ans,w);
 93         }
 94         if (ans == 0x3f3f3f3f) ans = 0;
 95         printf("%d\n",ans);
 96         return 0;
 97     }
 98     getmap();
 99     printf("%d\n",spfa(0,2*(m-1)*(n-1)+1));
100     return 0;
101 }

BZOJ1001 [BeiJing2006]狼抓兔子 平面圖轉對偶圖,最小割轉最短路