题解 P4298 [CTSC2008]祭祀

Posted colazcy

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了题解 P4298 [CTSC2008]祭祀相关的知识,希望对你有一定的参考价值。

题目链接

Solution [CTSC2008]祭祀

题目大意:求有向图最长反链,输出一种合法方案,以及一个点是否出现在至少一种合法方案里面

二分图


分析:

最长反链不好求,做个(Floyd)传递闭包,然后就是求最大点独立集了

然后(3min)淦了(CTSC)题?naive,毒瘤SPJ让你输出方案

第二问我们先找一个最大匹配,从左侧点的选没有被匹配的跑(dfs),每次从左到有走非匹配边,从右往左走匹配边。然后一路走一路标记,左边没有被标记过的点和右边被标记过的点就是最大点独立集

证明显然,匈牙利树不好想可以转成网络流

然后第三问,我们依次枚举删掉每一个点,如果删掉这个点之后答案减小了(1)那么这个点可能在最长反链中否则不可能

#include <cstdio>
#include <cstring>
#include <vector>
using namespace std;
const int maxn = 256,maxm = maxn * maxn;
vector<int> G[maxn];
inline void addedge(int from,int to){G[from].push_back(to);}
int n,m,ans,ban[maxn],match[maxn],vis[maxn],f[maxn][maxn],left[maxn],right[maxn];
inline bool find(int u){
    if(ban[u])return false;
    for(int v : G[u])
        if(!ban[v] && !vis[v]){
            vis[v] = 1;
            if(!match[v] || find(match[v])){
                match[v] = u;
                return true;
            }
        }
    return false;
}
inline void floyd(){
    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][k] && f[k][j]);
}
inline void build(){
    for(int u = 1;u <= n;u++)
        for(int v = 1;v <= n;v++)
            if(f[u][v])addedge(u,v);
}
inline void dfs(int u){
    if(left[u])return;
    left[u] = 1;
    for(int v : G[u])
        if(!right[v])right[v] = 1,dfs(match[v]);
}
int main(){
    scanf("%d %d",&n,&m);ans = n;
    for(int u,v,i = 1;i <= m;i++)
        scanf("%d %d",&u,&v),f[u][v] = 1;
    floyd();
    build();
    for(int i = 1;i <= n;i++)
        memset(vis,0,sizeof(vis)),ans -= find(i);
    printf("%d
",ans);
    memset(vis,0,sizeof(vis));
    for(int i = 1;i <= n;i++)
        vis[match[i]] = 1;
    for(int i = 1;i <= n;i++)
        if(!vis[i])dfs(i);
    for(int i = 1;i <= n;i++)
        printf("%d",left[i] && !right[i]);
    printf("
");
    for(int gg = 1;gg <= n;gg++){
        memset(match,0,sizeof(match));
        memset(ban,0,sizeof(ban));
        int tmp = 0;
        for(int i = 1;i <= n;i++)
            if(f[i][gg] || f[gg][i] || i == gg)ban[i] = 1;
            else tmp++;
        for(int i = 1;i <= n;i++)
            memset(vis,0,sizeof(vis)),tmp -= find(i);
        printf("%d",tmp == ans - 1);
    }
    return 0;
}

以上是关于题解 P4298 [CTSC2008]祭祀的主要内容,如果未能解决你的问题,请参考以下文章

BZOJ 1143: [CTSC2008]祭祀river 最大独立集

BZOJ1143: [CTSC2008]祭祀river

bzoj1143 [CTSC2008]祭祀river

1143: [CTSC2008]祭祀river(最长反链)

1143: [CTSC2008]祭祀river

[CTSC2008]祭祀river