bzoj 1001 [BeiJing2006]狼抓兔子

平面图最小割转对偶图最短路。

初看是一个裸的最小割,但数据范围1000000个点……

在原平面图上加入一条S到T的边,形成一个新区域。

将图上每个区域(二维)看做一个点(包括新区域和无限大的区域),区域边界看做边,边权为边界所对应原图中的边的边权,新建图。

删掉新区域和无限大区域之间的边。

此时原图最小割等于新图上新区域点到无限大区域点的最短路。

直观理解一下感觉挺对。

至于怎么实现上面的步骤,本题很简单随便搞一搞就行了,一般平面图的话就不(gen)再(ben)赘(bu)述(hui)了。

最后注意1*m和n*1的情况,此时根本没有区域,要特判。

  1 #include<iostream>
  2 #include<cstring>
  3 #include<cstdio>
  4 #include<algorithm>
  5 #include<queue>
  6 using namespace std;
  7 const int dian=2000005;
  8 const int bian=8000005;
  9 struct nd{
 10     int bh;
 11     int diss;
 12     bool operator < (const nd &rhs)const{
 13         return rhs.diss<diss;
 14     }
 15 };
 16 int h[dian],nxt[bian],ver[bian],val[bian],dis[dian],v[dian];
 17 int n,m,tot,aa;
 18 int S,T;
 19 void add(int a,int b,int c){
 20     tot++;ver[tot]=b;val[tot]=c;nxt[tot]=h[a];h[a]=tot;
 21 }
 22 void dijkstra(){
 23     memset(dis,0x3f,sizeof(dis));
 24     memset(v,0,sizeof(v));
 25     priority_queue<nd>q;
 26     dis[S]=0;
 27     nd hhd;
 28     hhd.bh=S;
 29     hhd.diss=0;
 30     q.push(hhd);
 31     while(!q.empty()){
 32         hhd=q.top();
 33         q.pop();
 34         int x=hhd.bh;
 35         if(v[x])
 36             continue;
 37         v[x]=1;
 38         for(int i=h[x];i;i=nxt[i]){
 39             int y=ver[i];
 40             if(dis[y]>dis[x]+val[i]){
 41                 dis[y]=dis[x]+val[i];
 42                 hhd.bh=y;
 43                 hhd.diss=dis[y];
 44                 q.push(hhd);
 45             }
 46         }
 47     }
 48 }
 49 int main(){
 50     memset(h,0,sizeof(h));
 51     memset(nxt,0,sizeof(nxt));
 52     tot=0;
 53     scanf("%d%d",&n,&m);
 54     if(n==1){
 55         int la=0x3f3f3f3f;
 56         for(int i=1;i<m;i++){
 57             scanf("%d",&aa);
 58             la=min(la,aa);
 59         }
 60         printf("%d",la);
 61         return 0;
 62     }
 63     if(m==1){
 64         int la=0x3f3f3f3f;
 65         for(int i=1;i<n;i++){
 66             scanf("%d",&aa);
 67             la=min(la,aa);
 68         }
 69         printf("%d",la);
 70         return 0;
 71     }
 72     S=n*m*2+1,T=n*m*2+2;
 73     for(int i=1;i<m;i++){
 74         scanf("%d",&aa);
 75         add(S,i,aa);
 76         add(i,S,aa);
 77     }
 78     for(int i=2;i<n;i++)
 79         for(int j=1;j<m;j++){
 80             scanf("%d",&aa);
 81             add(n*m+(i-2)*m+j,(i-1)*m+j,aa);
 82             add((i-1)*m+j,n*m+(i-2)*m+j,aa);
 83         }
 84     for(int i=1;i<m;i++){
 85         scanf("%d",&aa);
 86         add(n*m+(n-2)*m+i,T,aa);
 87         add(T,n*m+(n-2)*m+i,aa);
 88     }
 89     for(int i=1;i<n;i++)
 90         for(int j=1;j<=m;j++){
 91             scanf("%d",&aa);
 92             if(j==1){
 93                 add(T,n*m+(i-1)*m+j,aa);
 94                 add(n*m+(i-1)*m+j,T,aa);
 95             }
 96             else if(j==m){
 97                 add((i-1)*m+j-1,S,aa);
 98                 add(S,(i-1)*m+j-1,aa);
 99             }
100             else{
101                 add((i-1)*m+j-1,n*m+(i-1)*m+j,aa);
102                 add(n*m+(i-1)*m+j,(i-1)*m+j-1,aa);
103             }
104         }
105     for(int i=1;i<n;i++)
106         for(int j=1;j<m;j++){
107             scanf("%d",&aa);
108             add(n*m+(i-1)*m+j,(i-1)*m+j,aa);
109             add((i-1)*m+j,n*m+(i-1)*m+j,aa);
110         }
111     dijkstra();
112     printf("%d",dis[T]);
113     return 0;
114 }

 

posted @ 2017-01-06 17:45  dugudashen  阅读(223)  评论(0编辑  收藏  举报