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;}
0 0
原创粉丝点击