P4298 [CTSC2008]祭祀

P4298 [CTSC2008]祭祀

传递闭包跑一遍按联通建图

$(1)$最长反链长度=最小链覆盖=n-最大匹配

$(2)$定义作为最大匹配出现在左端点的集合为$S$,作为最大匹配出现在右端点的集合为$T$

定义函数$ft(x)$为$S$中任意点在$T$中的对应点,定义函数$fs(s)$为$T$中任意点在$S$中的对应点

先找最大匹配,从$S$的补集出发增广,当然这里增广不是真正意义上的增广,只是遍历并标记经过的点而已

左边没有标记过的或右边标记过的就是最小点覆盖,也就是最大独立集的补集

$(3)$枚举点,每次删掉在跑匹配就行

 My complete code: 

#include
#include
#include
using namespace std;
struct node{
    int to,next;
}edge[11000];
int n,m,ans,link,num,cnt,idx,ci; int dis[210][210],head[210],mat[210],to[210],s[210],t[210],visit[210];
bool del[210];
inline void add(int u,int v){
    edge[++cnt]=(node){v,head[u]}; head[u]=cnt;
}
bool dfs(int u){
    if(del[u])
        return false;
    for(int i=head[u];i;i=edge[i].next){
        int v=edge[i].to;
        if(visit[v]!=idx&&!del[v]){
            visit[v]=idx;
            if(!mat[v]){
                to[u]=v;
                mat[v]=u;
                return true;
            }else if(dfs(mat[v])){
                to[u]=v;
                mat[v]=u;
                return true;
            }
        }
    }
    return false;
}
void cal(int u){
    if(s[u])
        return;
    s[u]=1;
    for(int i=head[u];i;i=edge[i].next){
        int v=edge[i].to;
        if(t[v])
            continue;
        t[v]=1;
        cal(mat[v]);
    }
}
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;++i){
        int u,v;
        scanf("%d%d",&u,&v);
        dis[u][v]=1;
    }
    for(int k=1;k<=n;++k)
        for(int i=1;i<=n;++i)
            for(int j=1;j<=n;++j)
                dis[i][j]|=(dis[i][k]&dis[k][j]);
    for(int i=1;i<=n;++i)
        for(int j=1;j<=n;++j)
            if(dis[i][j])
                add(i,j);
    ans=n;
    idx=0;
    memset(del,false,sizeof(del));
    for(int i=1;i<=n;++i){
        ++idx;	
        if(dfs(i))
    		ans--;
    }
    printf("%d\n",ans);
    for(int i=1;i<=n;++i)
        if(!to[i])
            cal(i);
    for(int i=1;i<=n;++i)
        printf("%d",!t[i]&&s[i]);puts("");
    for(int i=1;i<=n;++i){
        memset(del,false,sizeof(del));
        memset(mat,0,sizeof(mat));
        memset(visit,0,sizeof(visit));
        int nn=0;
        for(int j=1;j<=n;++j)
            if(dis[i][j] || j==i || dis[j][i])
                del[j]=true;
            else
                nn++;
        idx=0;
        for(int j=1;j<=n;++j)
            if(!del[j]){
    			++idx;
        	    if(dfs(j))
            	    nn--;
            }
        if(nn==ans-1)
            printf("1");
        else
            printf("0");
    }
    return 0;
}

  

转载于:https://www.cnblogs.com/y2823774827y/p/10121831.html

你可能感兴趣的:(P4298 [CTSC2008]祭祀)