版权声明:抱最大的希望,为最大的努力,做最坏的打算。 https://blog.csdn.net/qq_37748451/article/details/88089040
题目来源:
http://poj.org/problem?id=3678
题意:
一个N个顶点和M条边的有向图,每个顶点能取0或1两个值.现在每条边被一个操作符(or,and,xor)以及一个值(0或1)标记了,表示a与b按操作符运算的结果是值(0或1).问你该有向图是否有可行解?
分析:
由于每个点只能取0或1两个值,所以我们把该问题转化为2-SAT问题.原图中的每个点对应2-SAT中的每个点.对于每种运算有下列转换方式:
a and b = 0 转换为 a=0 或 b=0
a and b = 1 转换为 a=1 且 b=1 (只要a为0或b为0必然引起矛盾)
a or b = 0 转换为 a+n->a b+n->b(只要a为1或b为1必然引起矛盾)
a or b = 1 转换为 a=1 或b=1
a xorb=0 转换为 a=1且b=1 或 a=0且b=0 即连下面的边:
a->b b->a a+n->b+n b+n->a+n.
a xor b=1 转换为a=1且b=0 或a=0且b=1 则连下面的边:
a+n->b b->a+n a->b+n b+n->a
代码:
#include<iostream>
#include<cstring>
#include<stack>
#include<iomanip>
#include<cmath>
#include<queue>
#include<algorithm>
#include<stdio.h>
using namespace std;
# define ll long long
const int maxn=41000;
int op[maxn],vis[maxn],low[maxn],dfn[maxn];
int pt[maxn],stk[maxn],color[maxn],pos[maxn],deg[maxn];
vector<int>vc[maxn],vc2[maxn];
int n,m,sig,cnt,tot,cont;
void add(int x,int y){
vc[x].push_back(y);
}
void top(){
memset(pt,0,sizeof(pt));
queue<int>s;
for(int i=1;i<=sig;i++){
if(deg[i]==0) s.push(i);
}
while(!s.empty()){
int u=s.front();
if(pt[u]==0){
pt[u]=1;
pt[pos[u]]=2;
}
s.pop();
for(int i=0;i<vc2[u].size();i++){
int v=vc2[u][i];
deg[v]--;
if(deg[v]==0) s.push(v);
}
}
cont=0;
for(int i=1;i<=n;i++) {
if(pt[color[i]]==1) op[cont++]=i;
}
}
void tarjan(int u){
vis[u]=1;
dfn[u]=low[u]=cnt++;
stk[++tot]=u;
for(int i=0;i<vc[u].size();i++){
int v=vc[u][i];
if(vis[v]==0) tarjan(v);
if(vis[v]==1) low[u]=min(low[u],low[v]);
}
if(low[u]==dfn[u]) {
sig++;
do{
vis[stk[tot]]=-1;
color[stk[tot]]=sig;
}while(stk[tot--]!=u);
}
}
void init(){
sig=0;cnt=1;tot=-1;
memset(deg,0,sizeof(deg));
memset(stk,0,sizeof(stk));
memset(dfn,0,sizeof(dfn));
memset(vis,0,sizeof(vis));
memset(color,0,sizeof(color));
for(int i=0;i<maxn;i++) {
vc[i].clear();
vc2[i].clear();
}
}
int solve(){
for(int i=1;i<=n*2;i++) {
if(vis[i]==0) tarjan(i);
}
for(int i=1;i<=n;i++) {
if(color[i]==color[i+n]) return 0;
pos[color[i]]=color[i+n];
pos[color[i+n]]=color[i];
}
for(int i=1;i<=n*2;i++){
for(int j=0;j<vc[i].size();j++){
int v=vc[i][j];
if(color[i]!=color[v]){
deg[color[i]]++;
vc2[color[v]].push_back(color[i]);
}
}
}
top();
return 1;
}
int main()
{
scanf("%d%d",&n,&m);
init();
for(int i=0;i<m;i++){
int x,y,z;
char op[10];
scanf("%d%d%d%s",&x,&y,&z,op);
x++;
y++;
/*int xx=x,yy=y;
if(x<0) x=-x;
if(y<0) y=-y;
if(xx>0&&yy>0) {add(x+n,y);add(y+n,x);}
if(xx>0&&yy<0) {add(x+n,y+n);add(y,x);}
if(xx<0&&yy>0) {add(x,y);add(y+n,x+n);}
if(xx<0&&yy<0) {add(x,y+n);add(y,x+n);}*/
if(op[0]=='A')
{
if(z==0)
{
add(x+n,y);
add(y+n,x);
}
else if(z==1)
{
add(x,x+n);
add(y,y+n);
}
}
else if(op[0]=='O')
{
if(z==0)
{
add(x+n,x);
add(y+n,y);
}
else if(z==1)
{
add(x,y+n);
add(y,x+n);
}
}
else if(op[0]=='X')
{
if(z==0)
{
add(x,y);
add(x+n,y+n);
add(y,x);
add(y+n,x+n);
/*TS.add_clause(a,0,b,0);
TS.add_clause(a,1,b,1);
TS.add_clause(b,0,a,0);
TS.add_clause(b,1,a,1);*/
}
else if(z==1)
{
/*TS.add_clause(a,0,b,1);
TS.add_clause(a,1,b,0);
TS.add_clause(b,0,a,1);
TS.add_clause(b,1,a,0);*/
add(x,y+n);
add(x+n,y);
add(y,x+n);
add(y+n,x);
}
}
}
if(solve()) printf("YES\n");
else printf("NO\n");
return 0;
}