BZOJ1143 [CTSC2008] 祭祀river
AC通道:http://www.lydsy.com/JudgeOnline/problem.php?id=1143
题目大意:
给你n个点,点与点之间由有向边相连。如果u能到达v的话,那么他们就不能同时选。问最多选多少个点。
[原题很强,可惜这里只有第一问,就变成大水题了...]
首先当然先跑一遍Floyd跑个传递闭包。
然后就是最大独立集了,最大独立集
最长反链
=最小路径覆盖数
=n-二分图最大匹配
然后就可以跑最大匹配了!
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int maxn=210; const int maxm=1010; const int INF=0x3f3f3f3f; struct Node{ int data,next,low; }node[maxn*maxn*2+2*maxn]; #define now node[point].data #define then node[point].next #define www node[point].low int n,m,cnt; int s,t,ans; int head[maxn],cur[maxn]; int dis[maxn],que[maxn]; bool f[maxn][maxn]; void add(int u,int v,int w){ node[cnt].data=v;node[cnt].next=head[u];node[cnt].low=w;head[u]=cnt++; node[cnt].data=u;node[cnt].next=head[v];node[cnt].low=0;head[v]=cnt++; } bool BFS(){ memset(dis,-1,sizeof(dis)); int H=0,T=1;que[1]=0;dis[s]=0; while(H<T){ H++; for(int point=head[que[H]];point!=-1;point=then) if(www && dis[now]<0){ dis[now]=dis[que[H]]+1; que[++T]=now; } } return dis[t]>0; } int dfs(int x,int low){ if(x==t) return low; int Low; for(int &point=cur[x];point!=-1;point=then) if(www && dis[now]==dis[x]+1){ Low=dfs(now,min(low,www)); if(Low){ www-=Low,node[point^1].low+=Low; return Low; } } return 0; } int main(){ #ifndef ONLINE_JUDGE freopen("1143.in","r",stdin); freopen("1143.out","w",stdout); #endif int u,v; scanf("%d%d",&n,&m); t=2*n+1; for(int i=s;i<=t;i++) head[i]=-1; for(int i=1;i<=n;i++) add(s,i,1),add(i+n,t,1); for(int i=1;i<=m;i++){ scanf("%d%d",&u,&v); f[u][v]=true; } for(int k=1;k<=n;k++) for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) f[i][j]=f[i][j]|(f[i][k]&f[k][j]); for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) if(f[i][j] && i!=j) add(i,j+n,1); int flag; while(BFS()){ for(int i=s;i<=t;i++) cur[i]=head[i]; while(flag=dfs(s,INF)) ans+=flag; } printf("%d",n-ans); return 0; }