• 洛谷 P3513 [POI2011]KONConspiracy(2sat方案数)


    传送门


    解题思路

    求2-sat合法的方案数。

    做法:

    先基操判断有无解,并求出一组解。

    然后考虑两个集合的人能否过去。

    我们发现只有三种情况:A到B一个人,B到A一个人,AB交换一个人。

    所以就 \(O(N^2)\) 判断AB集合中的人是否符合条件,最后方案数即为(A到B符合的人数+1)*(B到A符合的人数+1)+互换符合的情况数。

    注意2个人的情况需要特判,因为这既满足乘法也满足加法。

    AC代码

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<vector>
    #include<queue>
    #include<stack>
    #include<map>
    #include<bitset>
    using namespace std;
    template<class T>inline void read(T &x)
    {
        x=0;register char c=getchar();register bool f=0;
        while(!isdigit(c))f^=c=='-',c=getchar();
        while(isdigit(c))x=(x<<3)+(x<<1)+(c^48),c=getchar();
        if(f)x=-x;
    }
    template<class T>inline void print(T x)
    {
        if(x<0)putchar('-'),x=-x;
        if(x>9)print(x/10);
        putchar('0'+x%10);
    }
    const int maxn=10005;
    stack<int> s;
    int p[maxn],cnt,cntt[maxn],anss,ans[maxn],ans1,ans2,times,dfn[maxn],low[maxn],a[maxn],n,in[maxn],cnt_scc;
    bool vis[maxn][maxn];
    struct node{
    	int v,next;
    }e[maxn*maxn/2];
    void insert(int u,int v){
    	cnt++;
    	e[cnt].v=v;
    	e[cnt].next=p[u];
    	p[u]=cnt;
    }
    void dfs(int u){
    	dfn[u]=low[u]=++times;
    	s.push(u);
    	for(int i=p[u];i!=-1;i=e[i].next){
    		int v=e[i].v;
    		if(!dfn[v]){
    			dfs(v);
    			low[u]=min(low[u],low[v]);
    		}else{
    			if(!in[v]) low[u]=min(low[u],dfn[v]);
    		}
    	}
    	if(dfn[u]==low[u]){
    		cnt_scc++;
    		while(!s.empty()){
    			int x=s.top();s.pop();
    			in[x]=cnt_scc;
    			if(x==u) break;
    		}
    	}
    }
    int main(){
    	memset(p,-1,sizeof(p));
    	read(n);
    	for(int i=1;i<=n;i++){
    		int m;
    		read(m);
    		for(int j=1;j<=m;j++){
    			int x;
    			read(x);
    			vis[i][x]=1;
    		}
    		for(int j=1;j<=n;j++){
    			if(i==j) continue;
    			if(vis[i][j]){
    				insert(i+n,j);
    			}else{
    				insert(i,j+n);
    			}
    		}
    	}
    	for(int i=1;i<=2*n;i++) if(!in[i]) dfs(i);
    	for(int i=1;i<=n;i++){
    		if(in[i]&&in[i+n]&&in[i]==in[i+n]){
    			cout<<0<<endl;
    			return 0;
    		}
    		ans[i]=(in[i]<in[i+n]);
    	}
    	for(int i=1;i<=n;i++){
    		if(ans[i]==1){
    			for(int j=1;j<=n;j++){
    				if(i==j||ans[j]==1)  continue;
    				if(vis[i][j]) cntt[i]++,a[i]=j;
    			}
    		}
    		if(ans[i]==0){
    			for(int j=1;j<=n;j++){
    				if(i==j||ans[j]==0) continue;
    				if(!vis[i][j]) cntt[i]++,a[i]=j;
    			}
    		}
    	}
    	for(int i=1;i<=n;i++){
    		if(ans[i]==1){
    			if(cntt[i]==0) ans1++;
    			else if(cntt[i]==1&&cntt[a[i]]==0) anss++;
    		}
    		if(ans[i]==0){
    			if(cntt[i]==0) ans2++;
    			else if(cntt[i]==1&&cntt[a[i]]==0) anss++;
    		}
    	}
    	anss+=(ans1+1)*(ans2+1);
    	print((n==2?anss-1:anss));
    	return 0;
    }
    
  • 相关阅读:
    不同用户表的导入导出
    视图合并和谓词推入
    pgsql 的函数
    pgsql_pg的数据类型
    个人最终总结
    结对编程黄金点游戏
    阅读代码
    Visual Studio2015安装过程以及单元测试
    软件工程(2018)第五次团队作业
    软件工程(2018)第二次团队作业
  • 原文地址:https://www.cnblogs.com/yinyuqin/p/15426023.html
Copyright © 2020-2023  润新知