BZOJ 1001: [BeiJing2006]狼抓兔子 求平面图的最小割

题面

题意

给出一幅无向平面图,求s到t的最小割.
对偶图:将原图中的每一块区域当作一个点,原图上的每一条边转化为这条边两边区域之间的一条边,任何只在顶点处有交点的图(平面图)都有对偶图.

做法

这道题如果直接跑最大流,复杂度显然不对,但因为它存在对偶图,我们可以将题目转化为求左下角这块到右上角这块的最短路,对于样例可以这么建图
首先建对偶图
这里写图片描述
之后去掉原图就可以得到
这里写图片描述
可以发现从0点到13点((n-1)*(m-1) *2+1)的最短路恰好为最小割,这也是对偶图的一个性质,因此只要跑一边迪杰斯特拉即可.

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#define C ch=getchar()
#define INF 0x3f3f3f3f
#define P pair<int,int>
#define mp make_pair<int,int>
#define fi first
#define se second
#define N 1000100
using namespace std;

int n,m,first[N<<1],bb,t,s,d[N<<1];
bool vis[N<<1];
char ch;
P tmp;
struct Bn
{
    int to,next,quan;
} bn[N*6];
priority_queue<P,vector<P>,greater<P> >pq;

inline int read()
{
    int res;
    for(C;ch<'0';C);
    for(res=ch-'0',C;ch>='0';res=res*10+ch-'0',C);
    return res;
}

inline int ask(int u,int v,int w)
{
    return (u-1)*(n-1)*2+(v-1)*2+w+1;
}

inline void add(int u,int v,int w)
{
    bb++;
    bn[bb].to=v;
    bn[bb].next=first[u];
    bn[bb].quan=w;
    first[u]=bb;
}

inline void ad(int u,int v,int w)
{
    add(u,v,w);
    add(v,u,w);
}

int main()
{
    memset(first,-1,sizeof(first));
    int i,j,p,q;
    m=read(),n=read();
    t=(m-1)*(n-1)*2+1;
    for(i=1; i<=m; i++)
    {
        for(j=1; j<n; j++)
        {
            p=read();
            i==1?ad(ask(1,j,1),t,p):i==m?ad(ask(m-1,j,0),s,p):ad(ask(i-1,j,0),ask(i,j,1),p);
        }
    }
    for(i=1; i<m; i++)
    {
        for(j=1; j<=n; j++)
        {
            p=read();
            j==1?ad(s,ask(i,j,0),p):j==n?ad(ask(i,n-1,1),t,p):ad(ask(i,j-1,1),ask(i,j,0),p);
        }
    }
    for(i=1; i<m; i++)
    {
        for(j=1; j<n; j++)
        {
            ad(ask(i,j,0),ask(i,j,1),read());
        }
    }
    memset(d,0x3f,sizeof(d));
    pq.push(mp(0,s));
    d[s]=0;
    for(; !pq.empty()&&!vis[t];)
    {
        tmp=pq.top();
        pq.pop();
        q=tmp.se;
        if(vis[q]) continue;
        vis[q]=1;
        for(p=first[q]; p!=-1; p=bn[p].next)
        {
            if(d[bn[p].to]>d[q]+bn[p].quan)
            {
                d[bn[p].to]=d[q]+bn[p].quan;
                pq.push(mp(d[bn[p].to],bn[p].to));
            }
        }
    }
    cout<<d[t];
}

猜你喜欢

转载自blog.csdn.net/yzyyylx/article/details/80047444