zoukankan      html  css  js  c++  java
  • codeforces571C. CNF 2

    传送门:http://codeforces.com/problemset/problem/571/C

    思路:
    先去掉只出现一次的变量,贪心地使出现的表达式为真
    再去掉出现两次的且要求取值相同的变量,贪心地使两个表达式为真 
    现在只剩下出现两次且要求取值不同的变量
    把变量当作边,连接有它的两个表达式 
    现在就是要给该图的边定向,使每个点都有入边(即每个表达式成立) 
    构造,找到一个环,构造基环外向树即可 


    另一种写法是用二分图匹配,思路要清晰好想一些,但是代码长一点,先留个坑

    还是去掉只出现一次的变量和出现两次的且要求取值相同的变量

    变量是二分图的一边,表达式是二分图的另一边,给变量向有它的两个表达式连边,因为只能使一个成立,所以就是求二分图最大匹配,数据范围较大,要用HK算法(然而还不会...)

    /*
    先去掉只出现一次的变量,贪心地使出现的表达式为真
    再去掉出现两次的且要求取值相同的变量,贪心地使两个表达式为真 
    现在只剩下出现两次且要求取值不同的变量
    把变量当作边,连接有它的两个表达式 
    现在就是要给该图的边定向,使每个点都有入边(即每个表达式成立) 
    构造,找到一个环,构造基环外向树即可 
    */
    #include<vector>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define PI pair<int,int>
    #define mp(a,b) make_pair(a,b)
    #define fi first
    #define se second
    #define pb(a) push_back(a)
    #define abs(a) ((a)>0?(a):-(a))
    const int maxn=200010;
    using namespace std;
    int col[maxn],n,m,rely[maxn];bool flag[maxn],bo[maxn];vector<PI>a[maxn],f[maxn];
    //n表达式,m变量,flag[i]表达式i是否已成立,bo[i]表示变量i(建图后的边)是否已用过 
    //rely[i]构造的基环外向树中哪条边指向该点(构造哪个变量使这个表达式成立,于是就可以求出变量的值) 
    //a.fi变量的表达式,a.se使该表达式成立的取值 
    //f[i][j].fi i的第j条边连向的点,l[i][j].se i的第j条边对应的变量 
    
    bool dfs(int x){
    	flag[x]=1;//走到一个点就使与之相邻的一条边指向它,使之成立 
    	for (int i=0;i<f[x].size();i++){
    		int nowv=f[x][i].fi,nowx=f[x][i].se;
    		if (bo[nowx]) continue;
    		bo[nowx]=1;
    		if (flag[nowv]){rely[x]=nowx;return 1;}//另一个点不需要这条边就可成立,那么这条边可以给x点(已找到环或贪心时已成立) 
    		if (dfs(nowv)){rely[x]=nowx;return 1;}//能找到环,那么这条边也可以给x点 
    		rely[nowv]=nowx;//否则为了使下一个点成立,这条边要给下一个点 
    	}
    	return 0;//找不到环(与x相接的每条边都不能分配给x,总有表达式不成立) 
    }
    
    int main(){
    	scanf("%d%d",&n,&m);
    	for (int i=1,cnt,x;i<=n;i++){
    		scanf("%d",&cnt);
    		while (cnt--) scanf("%d",&x),a[abs(x)].pb(mp(i,x<0?0:1));
    	}
    	for (int i=1;i<=m;i++){
    		if (a[i].size()==0) continue;
    		if (a[i].size()==1) col[i]=a[i][0].se,flag[a[i][0].fi]=1;
    		if (a[i].size()==2){
    			if (a[i][0].se==a[i][1].se) col[i]=a[i][0].se,flag[a[i][0].fi]=flag[a[i][1].fi]=1;
    			else f[a[i][0].fi].pb(mp(a[i][1].fi,i)),f[a[i][1].fi].pb(mp(a[i][0].fi,i));
    		}
    	}
    	for (int i=1;i<=n;i++)
    		if(!flag[i]) 
    			if (!dfs(i)) return puts("NO"),0;
    	puts("YES");
    	for (int i=1;i<=n;i++)
    		if (rely[i]){
    			for (int j=0;j<a[rely[i]].size();j++)
    				if (a[rely[i]][j].fi==i) col[rely[i]]=a[rely[i]][j].se; 
    		}
    	for (int i=1;i<=m;i++) putchar('0'+col[i]);puts("");
    	return 0;
    }


  • 相关阅读:
    【尺取法】Jessica's Reading Problem
    【状态压缩】关灯问题2
    【AC自动机】多模匹配算法
    【蔡勒公式 】根据给定的年月日求出对应星期几
    【线段树】结训赛— H
    【快速幂 && 素数筛 && 数论】Carmichael Numbers
    【线段树】浅析--线段树
    【KMP】数据结构实验之串三:KMP应用
    【线段树】3771->数组计算机
    【字典树】2828 -> 字典树
  • 原文地址:https://www.cnblogs.com/thythy/p/5493516.html
Copyright © 2011-2022 走看看