POJ 3678 深刻理解2SAT

来源:互联网 发布:网络理财收益排行榜 编辑:程序博客网 时间:2024/06/03 17:54

感觉:这题看了一晚上了,看了所有的解题报告才明天怎么回事……昨天自学没理解好2SAT啊,所以连边不知道怎么连,而且看了别人的解题报告了也看不明白为什么要那样连,晕……

思路:因为给出结点 a ,b,值 c,还有判断方式OP,这种一看当然就知道是用2SAT做了。为什么说是深刻理解2SAT呢,因为……2SAT中说过,只有关系确定的才能连边,否则不能连边;还有一个重要的是,如果某个条件必须为某个值时,自身与自身的相反条件也要连边,具体看下面解释:

现在设 2*a为1,2*a+1为0;当然 2*b为1,2*b+1为0:

1.当OP为’And‘时:

(1)当c=1时,那么只有a 与 b同时为1时,a  AND b才等于1,并且有且只有当a与b都为1时这个条件才成立,所以a与b一定要等1,所以连边<2*a+1,2*a>,<2*b+1,2*b>,表示不管怎么样,a与b的情况都等于1,即:当a等于0时a必等于1,b等于0时b必等于1,这个刚开始我看别人的解题报告就是这么说的,然后自己也没太理解,其实真正的内涵就是强制执行a与b都等于1 !(如果a等于1了的话当然这条边就没用了,如果a等于0的话,那么这条连就可以起到把a强制等于1以符合题目条件情况了,就是如此简单,得慢慢理解)

(2)当c=0时,那么当a等于0时,b可能为0也可以为1,所以是不确定关系,由上面说的一定是确定关系才能连边,所以a为0的情况就不能连边了;当a等于1时,b一定为0才能使 a AND b =0,所以连边:<2*a,2*b+1>,当然还有<2*b,2*a,+1>。

2.当OP为OR时,

(1)当c=1时,那么当a=1时,b=1或者b=0,所以当a=1时出现了两种关系,就是不确定了,就不用连边了;当a=0时,那么b一定=1,所以是确定关系,连边:<2*a+1,2*b>,当然还有<2*b+1,2*a>。

(2)当c=0时,那么只有当a=b=0这个关系,所以这个和上面1(1)情况就一样了,上面是强制执行a=b=1的情况,而这里因为只有a=b=0的情况,所以也要强制执行a=b=0,即连边:<2*a,2*a+1>,<2*b,2*b+1>。

3.当OP为XOR时,因为如果a=1,那么b必=0;a=0,b必=1;b=1,a必=0;b=0,a必=1。如此看,这四个关系都是确定的,所以都要连边,但是其实我们可以不连,一条边都不用连,因为出a=1的时候一定不会再出现a=0了,这四条边是不会产生矛盾的,所以强连通缩点后不会出现belong[2*a]=belong[2*a+1]的情况的,所以连了也没用,只是多加了点判断的时间罢了……这在别人的解题报告里说的是形成了组环了,都是一个意思。比如:a=1,b=0与b=0,a=1在tarjan中会形成一个新的结点,也就是自环,所以……在异或这种情况中只能选择a=0或者a=1,所以不会出现矛盾……故不用连边了!

#include <iostream>#include <cstdio>#include <fstream>#include <algorithm>#include <cmath>#include <deque>#include <vector>#include <list>#include <queue>#include <string>#include <cstring>#include <map>#include <stack>#include <set>#define PI acos(-1.0)#define mem(a,b) memset(a,b,sizeof(a))#define sca(a) scanf("%d",&a)#define sc(a,b) scanf("%d%d",&a,&b)#define pri(a) printf("%d\n",a)#define lson i<<1,l,mid#define rson i<<1|1,mid+1,r#define MM 200005#define MN 2010#define INF 1000000007#define eps 1e-7using namespace std;typedef long long ll;int DFN[MN],vis[MN],LOW[MN],Stack[MN*10],belong[MN],tem,Count,top;vector<int>e[MN];void tarjan(int u){    DFN[u]=LOW[u]=++tem;    vis[u]=true;    Stack[++top]=u;    int v,i,l=e[u].size();    for(i=0;i<l;i++)    {        v=e[u][i];        if(!DFN[v])        {            tarjan(v);            LOW[u]=min(LOW[u],LOW[v]);        }        else if(vis[v]&&DFN[v]<LOW[u]) LOW[u]=DFN[v];    }    if(DFN[u]==LOW[u])    {        Count++;        do        {            v=Stack[top--];            vis[v]=false;            belong[v]=Count;        }while(v!=u);    }}bool twoSAT(int n){    for(int i=0;i<2*n;i++)        if(!DFN[i]) tarjan(i);    for(int i=0;i<n;i++)        if(belong[2*i]==belong[2*i+1]) return false;    return true;}int main(){    int n,m,i,a,b,c;    char s[5];    sc(n,m);    for(i=0;i<m;i++)    {        scanf("%d%d%d%s",&a,&b,&c,s);        if(s[0]=='A')        {            if(c)            {                e[2*a+1].push_back(2*a);                e[2*b+1].push_back(2*b);            }            else            {                e[2*a].push_back(2*b+1);                e[2*b].push_back(2*a+1);            }        }        else if(s[0]=='O')        {            if(c)            {                e[2*a+1].push_back(2*b);                e[2*b+1].push_back(2*a);            }            else            {                e[2*a].push_back(2*a+1);                e[2*b].push_back(2*b+1);            }        }    }    if(twoSAT(n)) puts("YES");    else puts("NO");    return 0;}



0 0
原创粉丝点击