zoukankan      html  css  js  c++  java
  • [洛谷P4782][题解]2-SAT问题

    题目

    0.定义

    先定义(k-SAT)问题:
    给出(n)个数和(m)个形如(x_1oplus x_2opluscdotsoplus x_k=0/1)的关系式((oplus)(land ,lor)等运算符),询问是否有解,如果有解,求出(x_1,x_2,cdots ,x_k)的值。
    (k>2)的已经证明是(NPC)了,我们只考虑(2-SAT)问题

    1.解法

    我们已经知道问题是什么样了,接下来该考虑怎么求了
    题中给的关系都不确定,我们考虑如何转成确定的关系
    遇到这类问题我们常常考虑拆点,那么不妨也在这题试试:
    把每个点(i)拆成(i,lnot i),然后考虑连边
    这里我们举一个很好理解的例子:(iland j=1),求(i,j)
    第一种情况:(i=0)
    此时(j)只能等于1,于是从(lnot i)连到(j)
    第二种情况:(j=0)
    此时(i)只能等于1,于是从(lnot j)连到(i)
    剩下的情况可以自己推一下,代码中用了一个比较方便的位运算简化版
    然后呢?
    首先判断是否有解
    可以很显然地想到:存在点(i)(lnot i)在一个强连通分量里(Leftrightarrow)无解
    这句话的意思就是如果有一个点为1,但是经过一些推导之后得到该点为0,那么就无解
    那么如果有解的话我们怎么求出这个解呢?
    直接亮出正解:选择(i,lnot i)中拓扑序较大的点
    因为(Tarjan)是回溯的时候记录,所以要输出编号小的

    2.代码

    省略了缺省源

    #define N 1000000 
    #define M 2000010
    int n,m,dfn[M],low[M],bel[M],ins[M],tim,num;
    struct Edge {
    	int nxt,to;
    }e[M];
    int head[M],cnt;
    inline void ade(int u,int v){
    	e[++cnt].to=v;
    	e[cnt].nxt=head[u];
    	head[u]=cnt;
    }
    stack<int>s;//以下为Tarjan板子 
    void Tarjan(int now){
    	dfn[now]=low[now]=++tim;
    	s.push(now),ins[now]=1;
    	for(rg int i=head[now];i;i=e[i].nxt){
    		int v=e[i].to;
    		if(!dfn[v]){
    			Tarjan(v);
    			low[now]=min(low[now],low[v]);
    		}else if(ins[v]){
    			low[now]=min(low[now],dfn[v]);
    		}
    	}
    	if(dfn[now]==low[now]){
    		num++;
    		do {
    			bel[now]=num;
    			now=s.top();
    			s.pop(),ins[now]=0;
    		}while(dfn[now]!=low[now]);
    	}
    }
    int main(){
    	Read(n),Read(m);
    	for(rg int i=1;i<=m;i++){
    		int a,b,ba,bb;
    		Read(a),Read(ba),Read(b),Read(bb);
    		ade(a+n*(ba&1),b+n*(bb^1));//小小的位运算简化代码 
    		ade(b+n*(bb&1),a+n*(ba^1));
    	}
    	for(rg int i=1;i<=(n<<1);i++){
    		if(!dfn[i])Tarjan(i);
    	}
    	for(rg int i=1;i<=n;i++){
    		if(bel[i]==bel[i+n]){//判断无解 
    			cout<<"IMPOSSIBLE"<<endl;
    			return 0;
    		}
    	}
    	cout<<"POSSIBLE"<<endl;
    	for(rg int i=1;i<=n;i++){//注意要用小于号 
    		cout<<(bel[i]<bel[i+n])<<" ";
    	}
    	return 0;
    }
    

    3.完结撒花

  • 相关阅读:
    k8s 组件介绍-kube-controller-manager
    k8s 组件介绍-API Server
    ELK+filebeat+redis 日志分析平台
    Logstash配置文件详情
    Logstash,Fluentd, Logtail对比伤害
    公司redis
    Linux之网络ping(unknown host)故障及yum no more mirrors to try
    Linux思维导图之计划任务
    Linux思维导图之进程管理
    Linux思维导图之网络管理
  • 原文地址:https://www.cnblogs.com/juruoajh/p/12725766.html
Copyright © 2011-2022 走看看