zoukankan      html  css  js  c++  java
  • 题解 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;
    }
    
  • 相关阅读:
    sql语句添加查询字段
    SqlServer Case when then用法总结
    单例与多线程
    HttpSession详解
    范式
    SQL语句中的Having子句与where子句
    HTTP无状态
    字节流与字符流的区别
    选择排序
    ReentrantLock VS synchronized
  • 原文地址:https://www.cnblogs.com/colazcy/p/11847765.html
Copyright © 2011-2022 走看看