• BZOJ2215: [Poi2011]Conspiracy


    BZOJ2215: [Poi2011]Conspiracy

    https://lydsy.com/JudgeOnline/problem.php?id=3832

    分析:

    • 这题好题啊。
    • 由观察得,假设有一个合法方案想要变成另一个合法方案。这个合法方案可以用(2sat)求。
    • 不能同时将(2)个或以上的同类型人换到对面去。
    • 因此枚举所有情况判断是否能换过去。
    • (S)为完全图集合,(T)为独立集合。
    • 考虑:
      1. (S)换一个到(T)
      1. (T)换一个到(S)
      1. (S)(T)互换一个。

    代码:

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <queue>
    #include <vector>
    using namespace std;
    #define N 10050
    template <typename T> void chkmax(T &x,T y) {if(x<y) x=y;}
    template <typename T> void chkmin(T &x,T y) {if(y<x) x=y;}
    int n;
    bool G[N][N],g[N>>1][N>>1];
    int dfn[N],low[N],S[N],ins[N],scc,bl[N],ln,fa[N],tp;
    int tot[N],h[N];
    void tarjan(int x) {
    	int i;
    	dfn[x]=low[x]=++dfn[0]; S[++tp]=x; ins[x]=1;
    	for(i=1;i<=ln;i++) if(G[x][i]) {
    		if(!dfn[i]) {
    			tarjan(i);
    			chkmin(low[x],low[i]);
    		}else if(ins[i]) chkmin(low[x],dfn[i]);
    	}
    	if(dfn[x]==low[x]) {
    		scc++; int t=0;
    		while(t!=x) {
    			t=S[tp--]; ins[t]=0; bl[t]=scc;
    		}
    	}
    }
    int main() {
    	scanf("%d",&n); ln=n<<1;
    	int i,x,y;
    	for(i=1;i<=n;i++) {
    		scanf("%d",&x);while(x--)scanf("%d",&y),g[i][y]=1;
    	}
    	int j;
    	for(i=1;i<=n;i++) {
    		for(j=i+1;j<=n;j++) {
    			if(g[i][j]) {
    				G[i+n][j]=1;
    				G[j+n][i]=1;
    			}else {
    				G[i][j+n]=1;
    				G[j][i+n]=1;
    			}
    		}
    	}
    	for(i=1;i<=ln;i++) if(!dfn[i]) tarjan(i);
    	for(i=1;i<=n;i++) {
    		if(bl[i]==bl[i+n]) {
    			puts("0"); return 0;
    		}
    		fa[i]=bl[i]>bl[i+n];
    	}
    	int ns=0,nt=0;
    	for(i=1;i<=n;i++) {
    		if(!fa[i]) ns++;
    		else nt++;
    	}
    	int ans=ns&&nt;
    	for(i=1;i<=n;i++) {
    		for(j=1;j<=n;j++) {
    			if(g[i][j]&&fa[i]!=fa[j]) {
    				tot[i]++;
    				h[i]=j;
    			}
    		}
    		if(!fa[i]) {
    			if(tot[i]==0&&ns>1) ans++;
    		}else {
    			if(tot[i]==ns&&nt>1) ans++;
    			else {
    				for(j=1;j<=n;j++) if(!g[i][j]&&fa[i]!=fa[j]) {h[i]=j; break;}
    			}
    		}
    	}
    	for(i=1;i<=n;i++) if(fa[i]==0) {
    		for(j=1;j<=n;j++) if(fa[j]==1) {
    			if((tot[i]==0|| (tot[i]==1&&h[i]==j) ) && ((tot[j]==ns|| (tot[j]==ns-1&&h[j]==i)) ) )ans++;
    		}
    	}
    	printf("%d
    ",ans);
    }
    
  • 相关阅读:
    (转载)Linux进程基础
    C语言字符串
    DNS域名解析服务
    Linux-SSH远程管理
    Linux文件系统深入了解
    Linux进程和计划任务管理
    Linux账户与权限管理
    MySQL实现读写分离
    SQL数据库常用函数
    MySQL进阶查询(二)
  • 原文地址:https://www.cnblogs.com/suika/p/10205229.html
Copyright © 2020-2023  润新知