题解
一道好题。
根据竞赛图性质可得,我们一定能在图中找到哈密顿路径,然后再利用竞赛图性质寻找强连通分量,并不断扩展环的大小。(这一步参见神犇博客:哈密顿问题)。
我们根据推断出,每个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);
}