平面圖我們離散課上講過,在二維空間中可以寫成不交叉邊的圖就是平面圖,最小的非平面圖有K5和K(3,3)
每個平面圖都對應一個對偶圖,對偶圖中的最小環就是原圖的最小割
如果刪去對偶圖中s-t這條邊,就是相當於求最短路了
把原圖中每個點在對偶圖中標號,重新建圖,在新圖中跑最短路就行了
然后看一下平面圖和對偶圖之間的轉化:
對偶圖中的每一個點即為平面圖中的某一個面,對偶圖中任意兩點間的線都是平面圖中對應兩平面公共邊的割線,如果平面圖中某一條邊只屬於一個面,那么在對偶圖中就是一個環邊
對偶圖的邊數等於平面圖的邊數,對偶圖的點數等於平面圖的面數
針對BZOJ1001
①把每一個圖中的面積塊當作新的點。
②每一條邊都與兩個面相連,把面看作點后,這條邊連接這兩個面化作的點,權值不變。
③連接起點與終點,把外面的最大平面分成兩份,分別為最短路的起點與終點。
④跑一邊最短路即可。
我感覺難在建圖上,別的都非常好說
建圖必須好好研究一下
1 #include<cstdio> 2 #include<cstring> 3 const int maxn=2000005; 4 int n,m,nm,cnt; 5 bool vi[maxn]; 6 int dis[maxn],g[maxn],q[maxn]; 7 struct Edge 8 { 9 int t,next,w; 10 }e[4*maxn]; 11 void insert(int u,int v,int w) 12 { 13 cnt++;e[cnt].t=v;e[cnt].w=w;e[cnt].next=g[u];g[u]=cnt; 14 cnt++;e[cnt].t=u;e[cnt].w=w;e[cnt].next=g[v];g[v]=cnt; 15 } 16 void spfa() 17 { 18 memset(dis,0x3f,sizeof(dis)); 19 dis[0]=0; 20 int h=0,t=1; 21 q[t]=0; 22 vi[0]=1; 23 while(h!=t) 24 { 25 h=h%maxn+1; 26 int u=q[h]; 27 vi[u]=0; 28 for(int tmp=g[u];tmp;tmp=e[tmp].next) 29 { 30 int v=e[tmp].t; 31 if(dis[v]>dis[u]+e[tmp].w) 32 { 33 dis[v]=dis[u]+e[tmp].w; 34 if(!vi[v]) 35 { 36 t=t%maxn+1; 37 vi[v]=1; 38 q[t]=v; 39 } 40 } 41 } 42 } 43 } 44 int main() 45 { 46 scanf("%d%d",&n,&m); 47 nm=(n*m-m-n+1)<<1; 48 int x; 49 for(int j=1;j<m;j++) 50 { 51 scanf("%d",&x); 52 insert(j,nm+1,x); 53 } 54 for(int i=1;i<n-1;i++) 55 { 56 for(int j=1;j<m;j++) 57 { 58 scanf("%d",&x); 59 insert((i<<1)*(m-1)+j,((i<<1)-1)*(m-1)+j,x); 60 } 61 } 62 for(int j=1;j<m;j++) 63 { 64 scanf("%d",&x); 65 insert(0,((n<<1)-3)*(m-1)+j,x); 66 } 67 for(int i=0;i<n-1;i++) 68 { 69 for(int j=1;j<=m;j++) 70 { 71 scanf("%d",&x); 72 if(j==1) insert(0,(i<<1)*(m-1)+m,x); 73 else if(j==m) insert((i<<1|1)*(m-1),nm+1,x); 74 else insert((i<<1)*(m-1)+j-1,(i<<1)*(m-1)+j+m-1,x); 75 } 76 } 77 for(int i=0;i<n-1;i++) 78 { 79 for(int j=1;j<m;j++) 80 { 81 scanf("%d",&x); 82 insert((i<<1|1)*(m-1)+j,(i<<1)*(m-1)+j,x); 83 } 84 } 85 spfa(); 86 printf("%d",dis[nm+1]); 87 return 0; 88 }