1 条题解

  • 0
    @ 2025-5-7 11:39:20

    题目大意是给点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
    上传者