POJ 3678 Katu Puzzle 2-SAT 强连通分量 tarjan

时间:2023-03-09 09:00:54
POJ 3678 Katu Puzzle 2-SAT 强连通分量 tarjan

http://poj.org/problem?id=3678

给m条连接两个点的边,每条边有一个权值0或1,有一个运算方式and、or或xor,要求和这条边相连的两个点经过边上的运算后的结果是边的权值。问存不存在使所有边都符合条件的给点赋值的方法。

2-SAT的各种连法都有了。

 #include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
const int maxn=;
int n,m;char s[]={};
struct nod{
int y,next;
}e[maxn*maxn];
int head[maxn]={},tot=;
inline void init(int x,int y){e[++tot].y=y;e[tot].next=head[x];head[x]=tot;}
int low[maxn]={},vis[maxn]={},dfn[maxn]={},cnt=;
int sta[maxn]={},tai=,bel[maxn]={},tn=;
void tarjan(int x){
low[x]=dfn[x]=++cnt;vis[x]=;sta[++tai]=x;
for(int i=head[x];i;i=e[i].next){
int y=e[i].y;
if(!dfn[y]){
tarjan(y);if(low[x]>low[y])low[x]=low[y];
}
else if(vis[y]&&dfn[y]<low[x])low[x]=dfn[y];
}
if(low[x]==dfn[x]){
int w;++tn;
do{
w=sta[tai--];
vis[w]=;bel[w]=tn;
}while(w!=x);
}
}
int main(){
scanf("%d%d",&n,&m);int x,y,v;
for(int i=;i<=m;i++){//x+n 1 x 0
scanf("%d%d%d",&x,&y,&v);scanf("%s",s);++x;++y;
if(s[]=='A'){
if(v==){
init(x+n,y+n);init(y+n,x+n);
init(y,x+n);init(x,y+n);
}else {init(x+n,y);init(y+n,x);}
}
else if(s[]=='O'){
if(v==){init(x,y+n);init(y,x+n);}
else{
init(x,y);init(y,x);
init(x+n,y);init(y+n,x);
}
}
else{
if(v==){
init(x,y+n);init(y+n,x);
init(x+n,y);init(y,x+n);
}
else{
init(x+n,y+n);init(y+n,x+n);
init(x,y);init(y,x);
}
}
}
for(int i=;i<=*n;i++)if(!dfn[i])tarjan(i);
int f=;
for(int i=;i<=n;i++){
if(bel[i]==bel[i+n]){
f=;break;
}
}
if(f)printf("NO\n");
else printf("YES\n");
return ;
}