[對偶圖最短路求最小割]BZOJ1001狼抓兔子

參考 https://blog.csdn.net/MaxMercer/article/details/77976666

平面圖纔有對偶圖。

平面圖是能展開成一張 -> 各邊只在頂點處相交的圖  <-的圖。

平面圖的對偶圖是將這個圖G的每一個面做新圖G‘的點,在 每一條邊兩邊的面之間連邊的圖。

隨便找個圖連一下會發現,對偶圖中的每一個環對應原圖中的一個割。

盜了一張論文ppt裏的圖。原圖爲藍色,對偶圖爲粉色。

現在我想求原圖S,T之間的最小割。假設原圖S,T之間有一條邊,對偶圖的S'和T’之間就會有一條切開這條邊的邊。只要我補上一條S'到T'之間的路徑,就形成了一個能把原圖S,T切開的環。由於要求最小割,那條假設的路徑權值可以不管,所以問題就轉化成了求對偶圖S'到T'的最短路徑問題。

我習慣spfa就寫了spfa。

 

/**************************************************************
    Problem: 1001
    User: adelais
    Language: C++
    Result: Accepted
    Time:2980 ms
    Memory:96996 kb
****************************************************************/
 
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=2000005;
const ll INF=1e18;
int n,m,cnt;
struct node{
    int to,ne,w;
}e[maxn*3];
int head[maxn];
ll dis[maxn];
bool fl[maxn];
queue<int>q;
void add(int u,int v,int w){
    e[cnt].to=v;e[cnt].w=w;
    e[cnt].ne=head[u];head[u]=cnt++;
    e[cnt].to=u;e[cnt].w=w;
    e[cnt].ne=head[v];head[v]=cnt++;
}
ll spfa(int s,int t){
    while(!q.empty()) q.pop();
    q.push(s);
    dis[s]=0;
    fl[s]=1;
    while(!q.empty()){
        int now=q.front();q.pop();
        fl[now]=0;
        for(int i=head[now];~i;i=e[i].ne){
            int v=e[i].to;
            if(dis[v]>dis[now]+e[i].w){
                dis[v]=dis[now]+e[i].w;
                if(!fl[v]){
                    fl[v]=1;q.push(v);
                }
            }
        }
    }
    return dis[t];
}
int main(){
    scanf("%d%d",&n,&m);
    int s=(n-1)*(m-1)*2+1,t=s+1;
    for(int i=0;i<=t;i++) head[i]=-1,dis[i]=INF;
    int x;
    for(int i=0;i<n;i++){
        for(int j=1;j<=m-1;j++){
            scanf("%d",&x);
            if(i==0) add(s,i*(m-1)*2+j*2,x);
            else if(i==n-1) add((i-1)*(m-1)*2+j*2-1,t,x);
            else add((i-1)*(m-1)*2+j*2-1,i*(m-1)*2+j*2,x);
        }
    }
    for(int i=0;i<n-1;i++){
        for(int j=1;j<=m;j++){
            scanf("%d",&x);
            if(j==1) add(t,i*(m-1)*2+j*2-1,x);
            else if(j==m) add(i*(m-1)*2+j*2-2,s,x);
            else add(i*(m-1)*2+j*2-2,i*(m-1)*2+j*2-1,x);
        }
    }
    for(int i=0;i<n-1;i++){
        for(int j=1;j<=m-1;j++){
            scanf("%d",&x);
            add(i*(m-1)*2+j*2-1,i*(m-1)*2+j*2,x);
        }
    }
 
    ll ans=spfa(s,t);
    printf("%lld\n",ans);
 
    return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章