【BZOJ】4727:[POI2017]Turysta-竞赛图&哈密顿回路

题解

一道好题。
根据竞赛图性质可得,我们一定能在图中找到哈密顿路径,然后再利用竞赛图性质寻找强连通分量,并不断扩展环的大小。(这一步参见神犇博客:哈密顿问题)。
我们根据推断出,每个scc(强连通分量)之间的连边必然是单向的(均为从某一scc的出边和另一scc的入边)。我们拓扑排序一下,对于每个点,先把它所在scc加入,再不断按拓扑序由大到小加入,就是答案了。


代码

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cctype>
#include<queue> 
#define inf 0x7fffffff
using namespace std;
const int N=2e5+10;
int a[102][102],d[255],tot=1,S,T,SS,TT,flow,mxflow;
int n,head[255],cur[255],to[N],nxt[N],w[N],in[255];
queue<int>Q;
inline int rd()
{
    char ch=getchar();int x=0,f=1;
    while(!isdigit(ch)){if(ch=='-') f=-1;ch=getchar();}
    while(isdigit(ch)){x=x*10+(ch^48);ch=getchar();}
    return x*f;
} 

inline void lk(int u,int v,int val)
{to[++tot]=v;nxt[tot]=head[u];head[u]=tot;w[tot]=val;}
inline int imin(int x,int y){return x>y?y:x;}

inline void build()
{
    int i,j;
    S=n+1;T=S+1;SS=S+2;TT=S+3;
    for(i=1;i<=n;++i) for(j=1;j<=a[i][0];++j) {
       lk(i,a[i][j],inf),lk(a[i][j],i,0);
       in[i]--;in[a[i][j]]++;
    }
    for(i=1;i<=n;++i){
        lk(S,i,inf);lk(i,S,0);lk(i,T,inf);lk(T,i,0);
        if(in[i]>0) lk(SS,i,in[i]),lk(i,SS,0);
        else lk(i,TT,-in[i]),lk(TT,i,0); 
    }
}

inline bool bfs(int s,int t)
{
    int i,j;
    for(i=1;i<=TT;++i) d[i]=-1;
    d[s]=0;Q.push(s);int x;
    while(!Q.empty()){
        x=Q.front();Q.pop();
        for(i=head[x];i;i=nxt[i]){
            j=to[i];
            if(d[j]==-1 && w[i]){
                d[j]=d[x]+1;
                Q.push(j);
            }   
        }
    } 
    return d[t]!=-1;  
}

inline int dfs(int s,int t,int f)
{
    if(s==t) return f;
    int ss=0,ret;
    for(int j,i=cur[s];i;i=nxt[i]){
        j=to[i];
        if(d[j]==d[s]+1 && w[i]){
            ret=f-ss;ret=dfs(j,t,imin(ret,w[i]));
            if(!ret){cur[s]=i;continue;}
            w[i]-=ret;w[i^1]+=ret;ss+=ret;
            if(ss==f) return f;
        }
    }
    if(!ss) d[s]=-1;
    return ss;
}

inline int dinic(int s,int t)
{
    int ret=0,i;
    while(bfs(s,t)){
        for(i=1;i<=TT;++i) cur[i]=head[i];
        ret+=dfs(s,t,inf);
    }
    return ret;
}

int main(){
    int i,j;
    n=rd();
    for(i=1;i<=n;++i){
        a[i][0]=rd();
        for(j=1;j<=a[i][0];++j)a[i][j]=rd();
    }
    build();
    lk(T,S,inf);lk(S,T,0);
    dinic(SS,TT); 
    mxflow=w[tot];
    head[S]=nxt[head[S]];head[T]=nxt[head[T]];
    for(i=head[SS];i;i=nxt[i]) w[i]=0,w[i^1]=0;
    for(i=head[TT];i;i=nxt[i]) w[i]=0,w[i^1]=0;
    lk(SS,T,inf);lk(T,SS,0);lk(S,TT,inf);lk(TT,S,0);
    flow=dinic(SS,TT);
    printf("%d\n",mxflow-flow);
}

猜你喜欢

转载自blog.csdn.net/corsica6/article/details/80556509