zoukankan      html  css  js  c++  java
  • 洛谷 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;
    }
    
  • 相关阅读:
    台州 OJ 3847 Mowing the Lawn 线性DP 单调队列
    洛谷 OJ P1417 烹调方案 01背包
    快速幂取模
    台州 OJ 2649 More is better 并查集
    UVa 1640
    UVa 11971
    UVa 10900
    UVa 11346
    UVa 10288
    UVa 1639
  • 原文地址:https://www.cnblogs.com/yinyuqin/p/15426023.html
Copyright © 2011-2022 走看看