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;
}
View Code

 

posted @ 2016-02-26 21:11  诚叙  阅读(286)  评论(0编辑  收藏  举报