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;
    }


  • 相关阅读:
    巴洛克式和哥特式的区别
    推荐阅读书籍,是时候再行动起来了。
    AtCoder ABC 159F Knapsack for All Segments
    AtCoder ABC 159E Dividing Chocolate
    AtCoder ABC 158F Removing Robots
    AtCoder ABC 158E Divisible Substring
    AtCoder ABC 157F Yakiniku Optimization Problem
    AtCoder ABC 157E Simple String Queries
    AtCoder ABC 157D Friend Suggestions
    AtCoder ABC 156F Modularness
  • 原文地址:https://www.cnblogs.com/thythy/p/5493516.html
Copyright © 2011-2022 走看看