对偶图 【BZOJ】1001: [BeiJing2006]狼抓兔子(对偶图+最短路)
http://www.lydsy.com/JudgeOnline/problem.php?id=1001
可謂慘不忍睹,一下午就在調這題了。
很久以前看到這題是一眼最大流,看到n<=1000,我也不管,我本著鍛煉代碼能力超時就超時的思想先寫了個最大流,TLE是很正常的。。
直到今天下午,我看了題解,原來是轉換成對偶圖跑最短路,恩,很巧妙的思想。(論文 周冬《兩極相通——淺析最大—最小定理在信息學競賽中的應用》)
首先介紹平面圖:
- 定義:圖中的一個點為源點s,另外一個點為匯點t,且s和t都在圖中的無界面的邊界上,我們稱這樣的平面圖為s-t平面圖。
- 性質:
對偶圖:G*中的每個點對應G中的一個面;對于G中的每條邊e,e屬于兩個面f1、f2,加入邊(f1*, f2*)
?舉例(圖中可能有錯誤,我指出來了):
根據它的性質,這些環對應的就是一個割,那么我們只要找一個“最短的”環,那么就找到最小割了~最大流也找到了。
跑一次最短路即可,spfa是O(km)k可看作常數(upd:我sb,O(km)是發論文那個人亂說的。。。。),那么時間就大大減小。(你用dij作到nlgn我也沒話說,反正spfa能過,你快點就快點。。)
那么如何建模呢?
我們將s和t連起來(自己畫圖連就行,實際操作不需要,能區分開來就行了),那么這個附加面我們設為s*,附加面外也就是無界面我們設為t*,按上面的方法連弧,跑一次s*到t*的最短路就行。
?
回到題目上來,此題變態,所以出現了一下TLE,一下RE,一下MLE,,,各種調試。。。各種靜態查錯。。好不容易a了。
ps:本題注意鏈的情況,即n==1或者m==1,那么面只有一個,即無界面,除非有特殊的技巧~不用特判,其實也就是當i=1或者j=1的時候,s和t在 “不存在的三角形”的編號內了,即s和t連接起來了,不會使得沒有邊連到s或者沒有邊連到t導致錯誤。
(此題空間跪了,我沒有自己算,全看標程怎么給的空間了,。,)
#include <cstdio> #include <cstring> #include <string> #include <iostream> #include <cmath> #include <algorithm> using namespace std; #define for1(i,a,n) for(i=a;i<=n;++i) #define for2(i,a,n) for(i=a;i<n;++i) #define for3(i,a,n) for(i=a;i>=n;--i) #define for4(i,a,n) for(i=a;i>n;--i) #define CC(i,a) memset(i,a,sizeof(i)) #define max(a,b) ((a)>(b)?(a):(b)) #define min(a,b) ((a)<(b)?(a):(b)) #define read(a) scanf("%d", &a) #define print(a) printf("%d", a)const int N=(999*999*2+2+10), M=N*3, oo=1000000000; int ihead[N], inext[M], to[M], w[M], cnt; int vis[N], q[M*2], front, tail, d[M], m;inline int num(const int &i, const int &j) {return ((m-1)*(i-1)<<1)+(j<<1)-1; }inline int getnum() {int ret=0; char c;for(c=getchar(); c<'0' || c>'9'; c=getchar());for(; c>='0' && c<='9'; c=getchar()) ret=ret*10+c-'0';return ret; }inline void add(int u, int v, int c) {inext[++cnt]=ihead[u]; ihead[u]=cnt; to[cnt]=v; w[cnt]=c;inext[++cnt]=ihead[v]; ihead[v]=cnt; to[cnt]=u; w[cnt]=c; }inline int spfa(int s, int t, int n) {CC(vis, 0);int u, i;for1(i, 0, n) d[i]=oo;vis[s]=1; front=tail=d[s]=0;q[tail++]=s;while(front<tail) {u=q[front++]; if(front==(M<<1)-10) front=0;for(i=ihead[u]; i; i=inext[i]) if(d[to[i]]>d[u]+w[i]) {d[to[i]]=d[u]+w[i];if(!vis[to[i]]) {vis[to[i]]=1, q[tail++]=to[i];if(tail==(M<<1)-10) tail=0;}}vis[u]=0;}return d[t]; }int main() {int n;n=getnum(); m=getnum();int i, j, c;int s=(n-1)*(m-1)*2+1, t=s+1;for1(i, 1, n) for2(j, 1, m) {c=getnum();if(i==1) add(num(i, j)+1, s, c);else if(i==n) add(num(i-1, j), t, c);else add(num(i, j)+1, num(i-1, j), c);}for2(i, 1, n) for1(j, 1, m) {c=getnum();if(j==1) add(num(i, j), t, c);else if(j==m) add(num(i, j-1)+1, s, c);else add(num(i, j), num(i, j)-1, c);}for2(i, 1, n) for2(j, 1, m) {c=getnum();add(num(i, j), num(i, j)+1, c);}print(spfa(s, t, t+1));printf("\n");return 0; }?
?
?
?
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 45 6 4
4 3 1
7 5 3
5 6 7 8
8 7 6 5
5 5 5
6 6 6
Sample Output
14HINT
Source
總結
以上是生活随笔為你收集整理的对偶图 【BZOJ】1001: [BeiJing2006]狼抓兔子(对偶图+最短路)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 全球域名服务商域名增量TOP10:中国占
- 下一篇: st是什么意思股票