1 条题解
-
0
题目大意是给点n个点和m个命题,对于每个命题都有其真假值和对应的运算关系—AND、OR、XOR,现在求是否存在解满足以上的命题。
按照题目要求,我们按下述原则进行建图: AND运算:
若a and b=0:若a=1,则b必为0,有边<a,b+n>;若b=1,则a必为0,有边<b,a+n>。 若a and b=1:a必为1且b必为1,有边<a+n,a>和<b+n,b>。 OR运算:
若a or b=0:a必为0且b必为0,有边<a,a+n>和<b,b+n>。 若a or b=1:若a为0,则b必为1,有边<a+n,b>;若b为0,则a必为1,有边<b+n,a>。 XOR运算
若a xor b=0,则有以下四种情况: 若a=0,则b必为0,即:<a+n,b+n>。 若a=1,则b必为1,即:<a,b>。 若b=0,则a必为0,即:<b+n,a+n>。 若b=1,则a必为0,即:<b,a>。 若a xor b=1,则有以下四种情况: 若 a = 0,则b必为1,即:<a+n,b> 若 a = 1,则b必为0,即:<a,b+n> 若 b = 0,则a必为1,即:<b+n,a> 若 b = 1,则a必为0,即:<b,a+n> 按照上述原则建完图后,用tarjan算法求得强连通分量,并判断对于问题i是否存在情况强连通分量编号scc[i]==scc[i+n],有则输出“NO”,无则输出“YES” ————————————————
//#include <bits/stdc++.h> #include <cstdio> #include <cstring> #include <algorithm> #include <stack> #define MAXN 2005 #define MAXM MAXN*MAXN using namespace std; struct Edge{ int v,next; Edge(){} Edge(int v,int next):v(v),next(next){} }edge[MAXM]; int EdgeCount,head[MAXN]; int n,m,block_cnt,scc_cnt; int dfn[MAXN],low[MAXN],scc[MAXN]; bool vis[MAXN]; stack<int> s; void addEdge(int u,int v) { edge[++EdgeCount]=Edge(v,head[u]); head[u]=EdgeCount; } void init() { memset(head,0,sizeof(head)); memset(dfn,0,sizeof(dfn)); memset(scc,0,sizeof(scc)); memset(vis,false,sizeof(vis)); EdgeCount=block_cnt=scc_cnt=0; } void get() { for(int i=1;i<=m;i++){ char op[5]; int a,b,val; scanf("%d%d%d%s",&a,&b,&val,op); if(op[0]=='A'){ //AND操作 if(val==0){ //a and b=0 addEdge(a,b+n); //a为1,b为0 addEdge(b,a+n); //b为1,a为0 } else{ //a and b=1 addEdge(a+n,a); //a必为1 addEdge(b+n,b); //b必为1 } } else if(op[0]=='O'){ //OR操作 if(val==0){ //a or b=0 addEdge(a,a+n); //a必为0 addEdge(b,b+n); //b必为0 } else{ //a or b=1 addEdge(a+n,b); //a为0,b为1 addEdge(b+n,a); //b为0,a为1 } } else{ //XOR操作 if(val==0){ //命a xor b=0 addEdge(a+n,b+n); //a为0,b为0 addEdge(b+n,a+n); //b为0,a为0 addEdge(a,b); //a为1,b为1 addEdge(b,a); //b为1,a为1 } else{ //a xor b=1 addEdge(a,b+n); //a为1,b为0 addEdge(b,a+n); //b为1,a为0 addEdge(a+n,b); //a为0,b为1 addEdge(b+n,a); //b为0,a为1 } } } } void tarjan(int u) { dfn[u]=low[u]=++block_cnt; //时间戳 vis[u]=true; //标记入栈 s.push(u); for(int i=head[u];i;i=edge[i].next){ int v=edge[i].v; if(!dfn[v]){ //还没访问过 tarjan(v); low[u]=min(low[u],low[v]); } else if(vis[v]) //已访问过且还在栈中 low[u]=min(low[u],dfn[v]); } if(dfn[u]==low[u]){ //满足强连通分量 scc_cnt++; while(1){ int tmp=s.top();s.pop(); scc[tmp]=scc_cnt; //标记所属强连通分量 vis[tmp]=false; //标记出栈 if(tmp==u)break; } } } bool TwoSat() { for(int i=0;i<2*n;i++) //s缩点 if(!dfn[i]) tarjan(i); for(int i=0;i<n;i++) if(scc[i]==scc[i+n]) //矛盾 return false; return true; } int main() { while(~scanf("%d%d",&n,&m)){ init(); //初始化 get(); //读入数据 if(TwoSat()) printf("YES\n"); else printf("NO\n"); } }
- 1
信息
- ID
- 2679
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者