Description
给出一系列的二元布尔运算,问所给变量是否存在可行解的情况。这些布尔运算有与、或和异或运算
Input
第一行两个整数n和m表示变量数以及运算数,之后m行每行一次运算a,b,tof,op表示变量a与变量b经过运算op结果为tof
Output
如果所有变量存在可行解则输出YES,否则输出NO
Sample Input
4 4
0 1 1 AND
1 2 1 OR
3 2 0 AND
3 0 0 XOR
Sample Output
YES
Solution
经典的2-sat问题。可以通过构造2-sat模型来求解。具体的建图规则为:
a and b ==1 , !a->a , !b -> b
a and b ==0 , a->!b , b->!a
a or b ==1 , !a->b , !b->a
a or b ==0 , a->!a , b->!b
a xor b ==1 , a->!b,!b->a,!a->b,b->!a
a xor b ==0 , a->b,b->a,!a->!b,!b->!a
接下来只需用tarjan算法求强联通分量并判断是否存在使得布尔公式值为真的一组布尔变量赋值即可
Code
#include<cstdio>
#include<cstring>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<stack>
#include<vector>
using namespace std;
#define maxn 2222
vector<int>g[maxn];
stack<int>st;
int n,m,scc,index;
int low[maxn],dfn[maxn],instack[maxn],fa[maxn];
void init()//初始化
{
scc=index=0;
while(!st.empty())st.pop();
for(int i=0;i<maxn;i++)g[i].clear();
memset(dfn,0,sizeof(dfn));
memset(instack,0,sizeof(instack));
memset(low,0,sizeof(low));
}
void tarjan(int u)//求强联通分量
{
dfn[u]=low[u]=++index;
instack[u]=1;
st.push(u);
int v,size=g[u].size();
for(int i=0;i<size;i++)
{
v=g[u][i];
if(!dfn[v])
{
tarjan(v);
low[u]=min(low[u],low[v]);
}
else if(instack[v])
low[u]=min(low[u],dfn[v]);
}
if(dfn[u]==low[u])
{
scc++;
do
{
v=st.top();
st.pop();
fa[v]=scc;
instack[v]=0;
}while(v!=u);
}
}
bool check()//判断可行性
{
for(int i=0;i<2*n;i++)//求强联通分量
if(!dfn[i])
tarjan(i);
for(int i=0;i<n;i++)
if(fa[i]==fa[n+i])
return false;
return true;
}
int main()
{
while(scanf("%d%d",&n,&m)!=EOF)
{
init();
for(int i=0;i<m;i++)
{
int u,v,tof;
char s[5];
scanf("%d%d%d%s",&u,&v,&tof,s);
if(s[0]=='A')
{
if(tof==1)
{
g[n+u].push_back(u);
g[n+v].push_back(v);
}
else if(tof==0)
{
g[u].push_back(n+v);
g[v].push_back(n+u);
}
}
else if(s[0]=='O')
{
if(tof==1)
{
g[n+u].push_back(v);
g[n+v].push_back(u);
}
else if(tof==0)
{
g[u].push_back(n+u);
g[v].push_back(n+v);
}
}
else if(s[0]=='X')
{
if(tof==1)
{
g[u].push_back(n+v);
g[n+v].push_back(u);
g[v].push_back(n+u);
g[n+u].push_back(v);
}
else if(tof==0)
{
g[u].push_back(v);
g[v].push_back(u);
g[n+v].push_back(n+u);
g[n+u].push_back(n+v);
}
}
}
if(check())
printf("YES\n");
else
printf("NO\n");
}
return 0;
}