1511 与或式
来源:互联网 发布:美股日内交易软件 编辑:程序博客网 时间:2024/06/02 02:11
51nod 1511 与或式
题目来源: CodeForces
基准时间限制:1 秒 空间限制:131072 KB 分值: 160 难度:6级算法题 收藏 关注
现在有一个与或式形式如下:
(v11|v12|…|v1k1) & (v21|v22|…|v2k2) & … & (vl1|vl2|…|vlkl)
&表示逻辑与,|表示逻辑或,vij是一些布尔变量或者是他们的取反。每一个括号内的表达式是一个块。
现在给定一个与或式和一些变量 x1,x2,…,xm 和他们的取反。每一个变量最多会出现在两个块中(变量本身和变量取反,比如 x1,¬x1 )。你的任务是判断一下是否有一组x的值使得这个与或式为真值。
样例解释:这个表达式是 (x1 | ¬x2)&(¬x1 | x2) 。其中一种解是 x1 = TRUE, x2 = TRUE。
Input
单组测试数据。
第一行包含两个整数 n 和m (1≤n,m≤2*10^5),表示块的个数和变量的个数。
接下来n行描述每一个块。
第i行先给出一个ki(ki≥1),表示第i个块中变量的个数。后面给出vij (1≤|vij|≤m),表示对应位置的变量是x[|vij|] ,如果vij是负的,就是表示取反,否则就是不取反。
Output
如果可以找到一组值,输出YES,否则输出NO。
Input示例
2 2
2 1 -2
2 2 -1
Output示例
YES
算法思想:
(v11|v12|…|v1k1) & (v21|v22|…|v2k2) & … & (vl1|vl2|…|vlkl)
只有各个块都为真时,整个表达式才为真。
因为一个变量只会出现两次,所以情况有限
1、只出现一次,那么那个表达式就能取1
2、一正一反,出现在一个表达式,那么这个表达式取1
3、一正一反,出现在两个不同的表达式中,不能确定表达式取值情况
4、两正或两反,变量所在的表达式肯定能取真值
根据上文分析,只有第三种情况是不能确定表达式取值情况的
对于n个表达式,n-1个变量在以只存在情况3,那么是整个表达式取不了真值的
x为e1,e2两个表达式共有的,一个表达式取真值,势必另一个表达式要取真值就不能依靠x来取得真值,
所以取得真值只能依靠其他变量,但是变量有限,所以不能所有表达式都取真值
所以,可以确定,n个不确定能否去真值的表达式,起码需要n个变量才能使所有表达式取值为真
所以,每两个表达式通过情况三产生关系时,就通过并查集联系起来,这样的话
一个集合中元素某一个确定可以取真值时,其他就可以取真值。
一个集合中两个元素还有情况三的变量时,集合中所有元素就可以取真值。
这次的算法思想写的应该是有史以来最详细的一次了-。-
#include<cstdio>const int N=200005;bool v[N];int f[N],fi[N],se[N];int read(){ int s=0,f=1; char c=getchar(); while(c!='-'&&(c<'0'||c>'9'))c=getchar(); if(c=='-')f=-1,c=getchar(); while(c>='0'&&c<='9')s=s*10+c-'0',c=getchar(); return f*s;}int find(int x){ return x==f[x]?x:f[x]=find(f[x]);}bool ok(int n){ int i,x; for(i=1;i<=n;i++) { x=find(i); if(!v[x]) { return 0; } } return 1;}int main(){ int i,j,k,x,y,n,m; n=read(),m=read(); for(i=1;i<=n;i++) f[i]=i; for(i=1;i<=n;i++) { k=read(); for(j=0;j<k;j++) { x=read(); if(x>0) { if(!fi[x])fi[x]=i; else se[x]=i; } else { if(!fi[-x])fi[-x]=-i; else se[-x]=-i; } } } for(i=1;i<=m;i++) { if(!fi[i])continue; if(se[i]) { if((fi[i]>0)==(se[i]>0)) { if(fi[i]<0)fi[i]=-fi[i]; if(se[i]<0)se[i]=-se[i]; x=find(fi[i]); y=find(se[i]); v[x]=v[y]=1; } else { if(fi[i]<0)fi[i]=-fi[i]; if(se[i]<0)se[i]=-se[i]; x=find(fi[i]); if(fi[i]==se[i]) v[x]=1; else { y=find(se[i]); if(x==y) v[x]=1; else { if(v[y])v[x]=1; f[y]=x; } } } } else { if(fi[i]<0)fi[i]=-fi[i]; x=find(fi[i]); v[x]=1; } } printf(ok(n)?"YES\n":"NO\n"); return 0;}
- 1511 与或式
- 与, 或, 异或
- 与或异或求补右移左移
- 与 或 非 异或
- 与 或 非 异或
- 与或非异或
- 位与、或、异或
- 【codeforce】异或 与 或
- 异或 、与、非、或
- 与,或,异或 学习
- 与或非亦或与交换
- 与或运算
- 与或非备忘
- 日志 与或
- 逻辑与或
- 与或遗漏问题
- 短路或|| 短路与&&
- 逻辑运算 或,与,非
- 大数据Spark “蘑菇云”行动第52课: Spark大型项目广告点击项目数据建模 项目!!!大项目!!!超大型大数据项目!!!
- Java根据概率、剩余奖品数量动态抽奖算法实现,概率总和可以不为100%
- Zookeeper 注册中心解析
- 15 个 Android 通用流行框架大全
- pache的Rewrite规则详细介绍
- 1511 与或式
- mysql保存不了微信表情符emoji问题解决方案
- 快速排序
- 仿御泥坊 完美实现电商类项目底部选项卡切换Fragment页面
- poj 2421(最小生成树 Prim算法)
- 算法导论九大排序总结
- Servlet的初步了解 --- JavaWeb
- SEO第二步——高质量外链
- $apply(转)