P4001 [BJOI2006]狼抓兔子

P4001 [BJOI2006]狼抓兔子


70分:

最小割=最大流

不会卡常,告辞

// luogu-judger-enable-o2
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#include<cctype>
using namespace std;
#define rg register
#define il inline
#define sta static
#define vd void
il int gi(){
    sta int x,flg;sta char ch;
    x=flg=0,ch=getchar();
    while(!isdigit(ch)){if(ch=='-')flg=-1;ch=getchar();}
    while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
    return flg?-x:x;
}
int id[1001][1001],S,T;
const int maxn=1000001,maxm=maxn*6+233;
int dep[maxn],fir[maxn],dis[maxm],nxt[maxm],w[maxm],ID=1;
il vd link(const int&x,const int&y,const int&z){
    nxt[++ID]=fir[x],fir[x]=ID,dis[ID]=y,w[ID]=z;
    nxt[++ID]=fir[y],fir[y]=ID,dis[ID]=x,w[ID]=z;
}
il bool BFS(){
    sta int que[maxn],hd=0,tl=0;
    for(rg int i=0;i^tl;++i)dep[que[i]]=-1;
    hd=tl=0;que[tl++]=S;dep[S]=1;
    while(hd^tl){
        sta int x;x=que[hd++];
        for(rg int i=fir[x];i;i=nxt[i])
            if(w[i]&&dep[dis[i]]==-1)dep[dis[i]]=dep[x]+1,que[tl++]=dis[i];
    }
    return ~dep[T];
}
il int Dinic(const int&x,int maxflow){
    if(x==T)return maxflow;
    int ret=0,d;
    for(rg int i=fir[x];i;i=nxt[i])
        if(w[i]&&dep[dis[i]]==dep[x]+1){
            d=Dinic(dis[i],min(w[i],maxflow-ret));
            ret+=d,w[i]-=d,w[i^1]+=d;
            if(ret==maxflow)return ret;
        }
    return ret;
}
int main(){
    int n=gi(),m=gi();
    for(rg int i=1;i<=n;++i)
        for(rg int j=1;j<=m;++j)
            id[i][j]=++id[0][0];
    for(rg int i=1;i<=n;++i)
        for(rg int j=1;j<m;++j)
            link(id[i][j],id[i][j+1],gi());
    for(rg int i=1;i<n;++i)
        for(rg int j=1;j<=m;++j)
            link(id[i][j],id[i+1][j],gi());
    for(rg int i=1;i<n;++i)
        for(rg int j=1;j<m;++j)
            link(id[i][j],id[i+1][j+1],gi());
    int ans=0;
    S=id[1][1],T=id[n][m];
    for(rg int i=1;i<=id[n][m];++i)dep[i]=-1;
    while(BFS())ans+=Dinic(S,2e9);
    printf("%d\n",ans);
    return 0;
}

100分:平面图转对偶图

不管A,B开头的点,这就是题目里的图,而且是个平面图

平面图就是可以搞成没有边相交的图(广告,ubuntu下平面图转对偶图练习:untangle

然后每个面建一个点,两个面有相交就连接两个面,边权为相交的边的权

如图红边组成对偶图

下面是结论:平面图最小割=对偶图最短路

(当然平面图最短路=对偶图最小割)

注意,平面图要求最小割必须再假装平面图的S-T(1-9)之间有一条边(又粗又黑的边)

然后这条边里面建一个S,另一半建个T就可以建图了

(这个题的图比较优秀 一般图怎么求对偶图呢 我也不知道)

然后用Dijk跑坠短路

(还有需要特判S=T的)

#include<bits/stdc++.h>
#define il inline
#define vd void
typedef long long ll;
il int gi(){
    int x=0,f=1;
    char ch=getchar();
    while(ch<'0'||ch>'9'){
        if(ch=='-')f=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
    return x*f;
}
int A[1001][1001],B[1001][1001];
const int maxn=2000010,maxm=1000001*6;
int fir[maxn],nxt[maxm],dis[maxm],w[maxm],S,T,ID;
il vd link(int x,int y,int z){
    static int id=0;
    nxt[++id]=fir[x];fir[x]=id;dis[id]=y;w[id]=z;
    nxt[++id]=fir[y];fir[y]=id;dis[id]=x;w[id]=z;
}
struct Queue{
    struct node{int x,y;}a[maxn];
    int siz,pos[maxn];
#define fa (x>>1)
#define ls (x<<1)
#define rs (x<<1|1)
    il vd Swap(int x,int y){
        std::swap(pos[a[x].y],pos[a[y].y]);
        std::swap(a[x],a[y]);
    }
    il vd pushup(int x){
        while(x!=1)
            if(a[x].x<a[fa].x)Swap(x,fa),x=fa;
            else break;
    }
    il vd pushdown(int x){
        while(ls<=siz){
            if(ls==siz||a[ls].x<a[rs].x){
                if(a[ls].x<a[x].x)Swap(x,ls),x=ls;
                else break;
            }else{
                if(a[rs].x<a[x].x)Swap(x,rs),x=rs;
                else break;
            }
        }
    }
    il int top(){return a[1].y;}
    il vd pop(){Swap(1,siz--);pushdown(1);}
    il vd change(int x,int y){
        x=pos[x];
        a[x].x=y;
        pushup(x);
    }
    il vd clear(int n){
        siz=n;for(int i=1;i<=n;++i)a[i]=(node){1e9,i},pos[i]=i;
        a[1]=(node){0,1};
    }
#undef fa
#undef ls
#undef rs
}que;
int dist[maxn];
bool vis[maxn];
il vd Dij(){
    memset(dist,63,sizeof dist);
    dist[S]=0;que.clear(ID);
    while(que.siz){
        int x=que.top();
        for(int i=fir[x];i;i=nxt[i]){
            if(dist[dis[i]]>dist[x]+w[i]){
                dist[dis[i]]=dist[x]+w[i];
                que.change(dis[i],dist[dis[i]]);
            }
        }
        que.pop();
    }
    printf("%d\n",dist[T]);
}
int main(){
    freopen("bjrabbit.in","r",stdin);
    freopen("bjrabbit.out","w",stdout);
    int n=gi(),m=gi();
    if(n==1||m==1){
        int ans=1e9;
        for(int i=1;i<std::max(n,m);++i)ans=std::min(ans,gi());
        printf("%d\n",ans);
        return 0;
    }
    S=++ID,T=++ID;
    for(int i=1;i<n;++i)
        for(int j=1;j<m;++j)
            A[i][j]=++ID;
    for(int i=1;i<n;++i)
        for(int j=1;j<m;++j)
            B[i][j]=++ID;
    for(int i=1;i<m;++i)link(S,B[1][i],gi());
    for(int i=1;i<n-1;++i)
        for(int j=1;j<m;++j)
            link(A[i][j],B[i+1][j],gi());
    for(int i=1;i<m;++i)link(A[n-1][i],T,gi());
    for(int i=1;i<n;++i){
        link(A[i][1],T,gi());
        for(int j=1;j<m-1;++j)
            link(B[i][j],A[i][j+1],gi());
        link(S,B[i][m-1],gi());
    }
    for(int i=1;i<n;++i)
        for(int j=1;j<m;++j)
            link(A[i][j],B[i][j],gi());
    Dij();
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/ssfdJR/p/9072853.html
今日推荐