• [POI2011]KON-Conspiracy


    题目传送门

    分析:
    求团+独立集?这是什么?
    冷静分析一波性质
    假设我们找到了一个合法方案,其中团的大小为(S),我们能否对(S)的大小进行变化
    发现(S)的大小变化不可能超过(1),如果有两个以上的人从独立集进入团,或者从团进入独立集,他们之间的连边关系会出现矛盾,导致不成立

    于是只会出现三种情况了:
    团里面的一个人进入独立集
    独立集里面的一个人进入团
    团和独立集里面各选一个人交换

    这三种情况枚举方案加在一起,表明答案大小是在(n^2)级别的,暴力枚举就可以了
    现在我们想办法求出一个合法方案

    考虑2-sat,设(i)为在团,(i')为在独立集
    如果(i,j)之间有连边,那么(i)在独立集中时,(j)就不能在独立集中,(i')(j)连边
    如果(i,j)之间无连边,那么(i)在团中时,(j)就不能在团中,(i)(j')连边
    跑一边2-sat判一下是否合法,然后缩点反向建图求方案
    剩下的就是暴力枚举了(写得没什么技术含量)

    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<vector>
    #include<queue>
    #include<iostream>
    #include<map>
    #include<bitset>
    #include<string>
    
    #define maxn 10005
    #define MOD 1000000007
    
    using namespace std;
    
    inline long long getint()
    {
        long long num=0,flag=1;char c;
        while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;
        while(c>='0'&&c<='9')num=num*10+c-48,c=getchar();
        return num*flag;
    }
    
    int n;
    bool vis[maxn],w[maxn>>1][maxn>>1];
    vector<int>G[maxn],scc[maxn],V[maxn];
    int dfn[maxn],low[maxn],sccno[maxn],clc,scccnt;
    int stk[maxn],tp;
    int d[maxn],c[maxn],sz1,sz2,p1[maxn],p2[maxn],ans;
    
    inline void tarjan(int u)
    {
    	dfn[u]=low[u]=++clc;stk[++tp]=u;
    	for(int i=0,v;i<G[u].size();i++)
    		if(!dfn[v=G[u][i]])tarjan(v),low[u]=min(low[u],low[v]);
    		else if(!sccno[v])low[u]=min(low[u],dfn[v]);
    	if(dfn[u]==low[u])
    	{
    		scccnt++;
    		while(1)
    		{
    			sccno[stk[tp]]=scccnt;
    			scc[scccnt].push_back(stk[tp]);
    			if(stk[tp--]==u)break;
    		}
    	}
    }
    
    inline void toposort()
    {
    	queue<int>Q;
    	for(int i=1;i<=scccnt;i++)if(!d[i])Q.push(i);
    	while(!Q.empty())
    	{
    		int u=Q.front();Q.pop();
    		for(int i=0;i<scc[u].size();i++)if(!vis[((scc[u][i]-1)^1)+1])vis[scc[u][i]]=1;
    		for(int i=0;i<V[u].size();i++)if(!(--d[V[u][i]]))Q.push(V[u][i]);
    	}
    }
    
    int main()
    {
    	n=getint();
    	for(int i=1;i<=n;i++)
    	{
    		int tmp=getint();
    		while(tmp--)w[i][getint()]=1;
    	}
    	for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)if(i!=j)
    		if(w[i][j])G[2*i].push_back(2*j-1);
    		else G[2*i-1].push_back(2*j);
    	for(int i=1;i<=2*n;i++)if(!dfn[i])tarjan(i);
    	for(int i=1;i<=n;i++)if(sccno[2*i]==sccno[2*i-1]){printf("0
    ");return 0;}
    	for(int i=1;i<=2*n;i++)for(int j=0;j<G[i].size();j++)
    		if(sccno[i]!=sccno[G[i][j]])V[sccno[G[i][j]]].push_back(sccno[i]),d[sccno[i]]++;
    	toposort();
    	for(int i=1;i<=n;i++)
    		if(vis[i*2-1])c[i]=1,sz1++;
    		else c[i]=2,sz2++;
    	if(sz1&&sz2)ans++;
    	for(int i=1;i<=n;i++)
    		if(c[i]&1)
    		{
    			bool p=0;
    			for(int j=1;j<=n;j++)if(c[j]==2&&w[i][j]){p=1;break;}
    			if(!p&&sz1>1)ans++,p1[i]=1;
    		}
    		else
    		{
    			bool p=0;
    			for(int j=1;j<=n;j++)if(c[j]==1&&!w[i][j]){p=1;break;}
    			if(!p&&sz2>1)ans++,p2[i]=1;
    		}
    	for(int i=1;i<=n;i++)for(int j=i+1;j<=n;j++)
    		if((p2[i]&&p1[j])||(p1[i]&&p2[j]))ans++;
    	printf("%d
    ",ans);
    }
    

  • 相关阅读:
    Python与机器视觉(x)图像修复
    git push代码到远程新分支
    1024节日快乐~~~~
    【Python-GPU】GPU数据科学加速包——RAPIDS
    Echarts漂亮水滴图
    【深度学习】三维点云数据集总结
    poj 3273 Monthly Expense
    poj 3150 Cellular Automaton
    poj 3101 Astronomy
    hdu 4282 A very hard mathematic problem
  • 原文地址:https://www.cnblogs.com/Darknesses/p/13027961.html
Copyright © 2020-2023  润新知