【题目大意】
n个布尔变量Xi,现在有m个约束条件,给出a op b = c,给出每个a b c 和 op。其中op可能是AND,OR,XOR。要求这n个布尔变量是否存在一组可能的取值,使得满足所有的约束条件。
【思路分析】
这题的构图的思路并不难,因为每个点就只有2种状态0或者1,所以构图就显得容易!我们设a为0,a'为1,b为0,b‘为1
那么根据3种操作符和c的值就可以构建下面这些边
AND c==1 a-->a' b-->b'这2条边表示a,b必须同时取1条件才成立
c==0 a'-->b b'-->a 第一条表示在a取1的情况下b必须取0,才能使a AND b为0,第2条边类推
OR c==1 a-->b' b-->a' 第一条边表示a取0的情况下b必须取1才能使结果为1,第2条边类推
c==0 a'-->a b'-->b 这2条边表示只有当a,b同时为0时条件才成立
XOR c==1 a-->b' a'-->b b-->a' b'-->a 表示只有a,b不同是条件才为1
c==0 a-->b a'-->b' b-->a b'-->a' 表示只有a,b相同时条件才为0
最后判断下相对2点是否在同一强连通分量重即可
【疑难解答】
(1)这题其他的构边都也许很好理解,就是AND c==1 a-->a' b-->b' OR c==0 a'-->a b'-->b 这2条边不能理解,为什么要这么构边?
嘿嘿,在说之前,先看看我原先错误的构边,我原来对于AND c==1这种情况是这样构边的 a'-->b' b'-->a'表示a为1的情况下b也为1,b为1的情况下a也为1条件才成立,表面上看没错,其实这是错误的构边方法,我的这种构边隐含的意思说a,b还可以有其他情况,a可以为0,b也可以为0,只不过在a为1 的情况下b必须为1,在b为1 的情况下a必须为1!其实不然,只要a为0或者b为0条件就不成立了,所以a,b必须同时为1,a和b的值是被固定死了的,a必须是1,b必须也是1,这个条件才成立,其他条件都不成立!所以构建 a-->a'表示a必须为1,b-->b' 表示b必须为1,条件才成立。我们可以从不相容点对看这种情况,在这种情况下不相容点对有3对 (a=0,b=0),(a=0,b=1)和(a=1,b=0)而在这3个不相容点对中构造的边都为同一条边 即a,b同时为1条件才成立,其他都不成立,也验证了上面这一点!
(2)为什么 a-->a'表示a必须为1,b-->b' 表示b必须为1
a'-->a其实就是表示0-->1选择了0必须选择1,我们从判断2-sat有无解的角度来看,当a 和a'在同一个强连通分量的时候就代表无解了,那么如果有个a'在某个强连通分量里,就代表该强连通分量选择了a'(1),那如果a也在这个强连通分量里的话就代表选择了a(0),对于其他条件来说a为0或者1都没有关系,这2者都可以选其一,而对于AND c==1 a-->a' b-->b' OR c==0 a'-->a b'-->b这2种情况来说是不行的,a,b的值必须固定!而我们增加了a'-->a这条边则可以产生了这一更严格要求,使a,b提前绑定!其实就是不能有条a'出去的路径回到a来,不能从1出去的路径回到0来,选择0(住:有条边指向0,就代表选择了0)!
源代码:
# include<cstdio>
# include<cstring>
# include<stack>
# include<vector>
using namespace std;
# define N 2005
int dfn[N],low[N],instack[N],belong[N],n,m,now,cnt;
vector<int> vec[N];
stack<int> sta;
inline int min(int a,int b)
{
return a<b?a:b;
}
void tarjan(int v)
{
int i,u;
dfn[v]=low[v]=++now;
sta.push(v);
instack[v]=1;
for(i=0;i<vec[v].size();i++)
{
u=vec[v][i];
if(!dfn[u])
{
tarjan(u);
low[v]=min(low[v],low[u]);
}
else if(instack[u])
low[v]=min(low[v],dfn[u]);
}
if(dfn[v]==low[v])
{
cnt++;
while(!sta.empty())
{
u=sta.top();
sta.pop();
instack[u]=0;
belong[u]=cnt;
if(u==v)
break;
}
}
}
int main()
{
int i,a,b,c,flag;
char s[5];
while(scanf("%d%d",&n,&m)!=EOF)
{
flag=now=cnt=0;
memset(instack,0,sizeof(instack));
memset(belong,0,sizeof(belong));
memset(low,0,sizeof(low));
memset(dfn,0,sizeof(dfn));
for(i=1;i<=m;i++)
{
scanf("%d%d%d%s",&a,&b,&c,s);
if(s[0]=='A')
{
if(c==1)
{
vec[2*a].push_back(2*a+1);
vec[2*b].push_back(2*b+1);
}
else if(c==0)
{
vec[2*a+1].push_back(2*b);
vec[2*b+1].push_back(2*a);
}
}
else if(s[0]=='O')
{
if(c==1)
{
vec[2*a].push_back(2*b+1);
vec[2*b].push_back(2*a+1);
}
else if(c==0)
{
vec[2*a+1].push_back(2*a);
vec[2*b+1].push_back(2*b);
}
}
else
{
if(c==1)
{
vec[2*a].push_back(2*b+1);
vec[2*a+1].push_back(2*b);
vec[2*b].push_back(2*a+1);
vec[2*b+1].push_back(2*a);
}
else
{
vec[2*a].push_back(2*b);
vec[2*b].push_back(2*a);
vec[2*a+1].push_back(2*b+1);
vec[2*b+1].push_back(2*a+1);
}
}
}
for(i=0;i<2*n;i++)
if(!dfn[i])
tarjan(i);
for(i=0;i<2*n;i+=2)
if(belong[i]==belong[i+1])
{
flag=1;
break;
}
if(flag)
printf("NO\n");
else
printf("YES\n");
for(i=0;i<2*n;i++)
vec[i].clear();
while(!sta.empty())
sta.pop();
}
return 0;
}