BZOJ1001: [BeiJing2006]狼抓兔子 (最小割转最短路)
↑方法介绍
对于一个联通的平面图G(满足欧拉公式) 在s和t间新连一条边e;
然后建立一个原图的对偶图G*,G*中每一个点对应原图中每一个面,每一条边对应分割面的每一条边;
那么对偶图G*中,以原图s和t间边e新划分出的面作为起点(s*),最外的面作为终点(t*);
那么从s*到t*的每一条路都是原图G的一个割;
下图来自上方标出百度文库网址的ppt;
然后用堆(优先队列)优化的迪杰斯特拉,复杂度 O((m+n)logn) n为点数,m为边数...
嗯存一个堆优化迪杰斯特拉的代码...很久以前那个没有标签的一通好找..
1 #include<cmath> 2 #include<cstdio> 3 #include<cstring> 4 #include<iostream> 5 #include<algorithm> 6 #include<queue> 7 using namespace std; 8 #define pa pair<int,int> 9 int n,m,s,t; 10 struct node{ 11 int y; 12 int next; 13 int v; 14 }e[6000100]; 15 int head[2000100]={},tot=0,dis[2000100]={}; 16 bool vis[2000100]={}; 17 priority_queue< pa, vector< pa >, greater< pa > >q; 18 inline void init(int x,int y,int v){ 19 e[++tot].y=y; 20 e[tot].next=head[x]; 21 e[tot].v=v; 22 head[x]=tot; 23 } 24 inline int ge(int x,int y,int k){//x行,y列,在斜线的左(1)右(2);返回格子的编号 25 return 2*(x-1)*(m-1)+2*(y-1)+k; 26 } 27 /* 28 事实上如果按照从上到下从左到右来编号,在输入时的块编号是有规律的; 29 不一定要像上面一样这样找格子编号; 30 */ 31 void doit(){ 32 memset(dis,63,sizeof(dis)); 33 int x,y; 34 dis[s]=0; 35 q.push(make_pair(0,s)); 36 while(!q.empty()){ 37 x=q.top().second; 38 q.pop(); 39 if(vis[x]){ 40 continue; 41 } 42 vis[x]=1; 43 for(int i=head[x];i;i=e[i].next){ 44 y=e[i].y; 45 if(dis[y]>dis[x]+e[i].v){ 46 dis[y]=dis[x]+e[i].v; 47 vis[y]=0; 48 q.push(make_pair(dis[y],e[i].y)); 49 } 50 } 51 } 52 } 53 int main(){ 54 scanf("%d%d",&n,&m); 55 int v; 56 t=(m-1)*(n-1)*2+2; 57 s=t-1; 58 for(int i=1;i<=n;i++){ 59 for(int j=1;j<m;j++){ 60 scanf("%d",&v); 61 if(i==1){ 62 init(s,2*j,v); 63 init(2*j,s,v); 64 }else if(i==n){ 65 init(ge(n-1,j,1),t,v); 66 init(t,ge(n-1,j,1),v); 67 }else{ 68 init(ge(i-1,j,1),ge(i,j,2),v); 69 init(ge(i,j,2),ge(i-1,j,1),v); 70 } 71 } 72 } 73 for(int i=1;i<n;i++){ 74 for(int j=1;j<=m;j++){ 75 scanf("%d",&v); 76 if(j==1){ 77 init(t,ge(i,1,1),v); 78 init(ge(i,1,1),t,v); 79 }else if(j==m){ 80 init(ge(i,m-1,2),s,v); 81 init(s,ge(i,m-1,2),v); 82 }else{ 83 init(ge(i,j-1,2),ge(i,j,1),v); 84 init(ge(i,j,1),ge(i,j-1,2),v); 85 } 86 } 87 } 88 for(int i=1;i<n;i++){ 89 for(int j=1;j<m;j++){ 90 scanf("%d",&v); 91 init(ge(i,j,1),ge(i,j,2),v); 92 init(ge(i,j,2),ge(i,j,1),v); 93 } 94 } 95 doit(); 96 printf("%d\n",dis[t]); 97 return 0; 98 }