網路流之轉換為對偶圖
網路流之轉換為對偶圖
先來觀察下面的這張圖:
下面的這張卻完全不行。
像這樣任意兩邊的交點在頂點上的圖我們稱為平面圖。
幾條邊圍成一個區域,這個區域稱為一個面。
對平面圖,我們定義對偶圖:
下圖中黑色的是個平面圖,紅色的就是對偶圖。其建立方法是,對每個面建一個點,只要有一條邊是在兩個面之間,我們就對這兩個面對應的點連邊(稍有些繞)。注意是有一條邊就連線。
然後我們就得到萌萌噠的對偶圖一張!
對偶圖就有很多美妙的性質了。比如說,我們發現,對偶圖的一條邊就對應了一條割邊。
既然如此的話,想想狼抓兔子,一條割邊有一個容量,那麼如果我們建它的對偶圖,最短路就是最小割。
所以得出下面的重要定理:
對平面圖來說,最大流 = 最小割 = 對偶圖最短路
所以我們就可以穩一些跑出來狼抓兔子。
1001: [BeiJing2006]狼抓兔子
Time Limit: 15 SecMemory Limit: 162 MB
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
HOME Back
題目分析:
,每一個環中間都有一個點(類似於圓方樹?) 然後每一條邊會被相鄰兩個環中的點給穿插。最後我們要建立源點和匯點,讓後讓那些沒有沒有相鄰環的連源匯點。
這就是題目所給圖的對偶圖;
只要求源點到匯點的最短路徑即可;
參考程式碼:
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int N=2000006,INF=0x3fffffff,E=N*3; 4 struct ARC { 5int u, val, next; 6inline void init(int a, int b, int c) { 7u=a, val=b, next=c; 8} 9 } arc[E]; 10 int head[N], tot, S, T, n, m, dis[N]; 11 bool vs[N]; 12 13 struct data{ 14int u, dis; 15data() {} 16data(int a, int b) : u(a), dis(b) {} 17bool operator < (const data &T) const { 18return dis>T.dis; 19} 20 }; 21 22 inline void add_arc(int s, int t, int val) 23 { 24arc[tot].init(t, val, head[s]); 25head[s]=tot++; 26 } 27 28 priority_queue<data> Q; 29 void Dijkstra() 30 { 31fill(dis, dis+T+1, INF); 32fill(vs, vs+T+1, 0); 33while(!Q.empty()) Q.pop(); 34dis[S]=0, Q.push(data(S, 0)); 35for(int u; !Q.empty(); ) 36{ 37u=Q.top().u, Q.pop(); 38if(vs[u]) continue; 39if(u==T) 40{ 41printf("%d\n", dis[T]); 42break; 43} 44vs[u]=1; 45for(int e=head[u]; e!=-1; e=arc[e].next) { 46int v=arc[e].u; 47if(vs[v] || dis[u]+arc[e].val>=dis[v]) continue; 48dis[v]=dis[u]+arc[e].val; 49Q.push(data(v, dis[v])); 50} 51} 52 } 53 54 void read(int &x) { 55char c; 56while((c=getchar())<'0' || c>'9'); 57x=c-'0'; 58while((c=getchar())>='0' && c<='9') x=(x<<3)+(x<<1)+c-'0'; 59 } 60 61 void Input() { 62for(int i=0, id1, id2, a; i<=n-1; i++) 63for(int j=1; j<=m-1; j++) { 64read(a); 65id1=((i-1)*(m-1)+j)*2-1; 66id2=(i*(m-1)+j)*2; 67if(i==0) id1=T; 68else if(i==n-1) id2=S; 69add_arc(id1,id2,a); 70add_arc(id2,id1,a); 71} 72 73for(int i=1, id1, id2, a; i<=n-1; i++) 74for(int j=0; j<m; j++) { 75read(a); 76id1=((i-1)*(m-1)+j)*2; 77id2=((i-1)*(m-1)+j+1)*2-1; 78if(j==0) id1=S; 79else if(j==m-1) id2=T; 80add_arc(id1, id2, a); 81add_arc(id2, id1, a); 82} 83 84for(int i=1, id1, id2, a; i<=n-1; i++) 85for(int j=1; j<=m-1; j++) { 86read(a); 87id1=((i-1)*(m-1)+j)*2; 88id2=((i-1)*(m-1)+j)*2-1; 89add_arc(id1, id2, a); 90add_arc(id2, id1, a); 91} 92 } 93 94 int main() { 95read(n), read(m); 96S=0, T=(n-1)*(m-1)*2+1; 97fill(head, head+T+1, -1), tot=0; 98if(n==1 || m==1) 99{ 100if(n>m) swap(n, m); 101int ans=INF; 102for(int i=1, a; i<m; i++) 103{ 104read(a); 105if(ans>a) ans=a; 106} 107printf("%d\n", ans==INF?0:ans); 108} 109else Input(), Dijkstra(); 110return 0; 111 } View Code