[BZOJ]1143: [CTSC2008]祭祀river

时间:2022-09-03 14:16:12

题目大意:给定一个n个点m条边的有向无环图,问最多选多少个点使得两两之间互不到达。(n<=100,m<=1000)

思路:题目所求即最长反链,最长反链=最小链覆盖,对每个点向自己能到的所有点连边后,转化成最小路径覆盖,每个点拆成入点和出点后二分图匹配,又有最大二分图匹配=最小路径覆盖,问题得到解决。复杂度O(nm+MaxFlow(n,n^2))。

#include<cstdio>
#include<cstring>
inline int read()
{
int x;char c;
while((c=getchar())<''||c>'');
for(x=c-'';(c=getchar())>=''&&c<='';)x=(x<<)+(x<<)+c-'';
return x;
}
#define MN 100
#define MM 1000
#define MV 200
#define ME 10000
#define S MV+1
#define T MV+2
#define INF 0x7FFFFFFF
namespace MaxFlow
{
struct edge{int nx,t,w;}e[ME*+];
int h[MV+],en=,d[MV+],q[MV+],qn,c[MV+];
inline void ins(int x,int y,int w)
{
e[++en]=(edge){h[x],y,w};h[x]=en;
e[++en]=(edge){h[y],x,};h[y]=en;
}
bool bfs()
{
int i,j;
memset(d,,sizeof(d));
for(d[q[i=qn=]=S]=;i<=qn;++i)for(j=c[q[i]]=h[q[i]];j;j=e[j].nx)
if(e[j].w&&!d[e[j].t])d[q[++qn]=e[j].t]=d[q[i]]+;
return d[T];
}
int dfs(int x,int r)
{
if(x==T)return r;
int k,u=;
for(int&i=c[x];i;i=e[i].nx)if(e[i].w&&d[e[i].t]==d[x]+)
{
k=dfs(e[i].t,r-u<e[i].w?r-u:e[i].w);
u+=k;e[i].w-=k;e[i^].w+=k;
if(u==r)return r;
}
return d[x]=,u;
}
int dinic(){int ans=;while(bfs())ans+=dfs(S,INF);return ans;}
};
struct edge{int nx,t;}e[MM+];
int h[MN+],en,q[MN+],qn,u[MN+];
inline void ins(int x,int y){e[++en]=(edge){h[x],y};h[x]=en;}
int main()
{
int n,m,i,j,k,x,y;
n=read();m=read();
while(m--)x=read(),y=read(),ins(x,y);
using MaxFlow::ins;
for(i=;i<=n;++i)
{
ins(S,i,);ins(i+n,T,);
memset(u,,sizeof(u));
for(u[q[j=qn=]=i]=;j<=qn;++j)for(k=h[q[j]];k;k=e[k].nx)
if(!u[e[k].t])ins(i,e[k].t+n,INF),u[q[++qn]=e[k].t]=;
}
printf("%d",n-MaxFlow::dinic());
}