2-sat

详解

关键点

注意我们要在两种取值中选择拓扑序较大的那个值,因为这样才能保证结果最优
其实我们在 𝑇𝑎𝑟𝑗𝑎𝑛的时候就已经求出了强联通分量的拓扑序了,只不过是反序;
拓扑序越大的点在一棵树上是越靠近叶节点的,然后越靠近叶节点的那些节点在 𝑇𝑎𝑟𝑗𝑎𝑛的时候是越早被缩点的,所以拓扑序越大的点其所在强联通分量编号越小)
那么我们只要取两个取值中强联通分量编号较小的所对应的值就可以了;(这是保证不会错的,因为有时候两个值取哪个都行)

应用

  1. 2-sat模版luogu
点击查看代码
#include<functional>
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<string>
#include<cstdio>
#include<vector>
#include<cmath>
#include<queue>
#include<deque>
#define ll long long 
using namespace std;
const int maxn=3e6+101;
const int MOD=998244353;
const int inf=2147483647;
int read(){
    int x=0,f=1;char ch=getchar();
    for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
    for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';
    return x*f;
}
int n,m;
int tot,head[maxn],nx[maxn],to[maxn];
void add(int x,int y){to[++tot]=y;nx[tot]=head[x];head[x]=tot;}
int dfn[maxn],co[maxn],cnt,st[maxn],top,low[maxn],sum;
void tarjan(int u){
    low[u]=dfn[u]=++sum;
    st[++top]=u;
    for(int i=head[u];i;i=nx[i]){
        int k=to[i];
        if(!dfn[k]){
            tarjan(k);
            low[u]=min(low[u],low[k]);
        }
        else if(!co[k])low[u]=min(low[u],dfn[k]);
    }
    if(low[u]==dfn[u]){++cnt;while(!co[u]){co[st[top--]]=cnt;}}
    return ;
}
int main(){
    n=read();m=read();
    for(int i=1;i<=m;i++){
        int x=read(),a=read();
        int y=read(),b=read();
        add(x+(a^1)*n,y+b*n);
        add(y+(b^1)*n,x+a*n);
    }
    for(int i=1;i<=n*2;i++){if(!dfn[i])tarjan(i);}
    for(int i=1;i<=n;i++){
        if(co[i]==co[i+n]){printf("IMPOSSIBLE");return 0;}
    }
    printf("POSSIBLE\n");
    for(int i=1;i<=n;i++){
        if(co[i]<co[i+n])printf("0 ");
        else printf("1 ");
    }
    return 0;
}
2. 和平委员会luogu
点击查看代码
#include<functional>
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<string>
#include<cstdio>
#include<vector>
#include<cmath>
#include<queue>
#include<deque>
#define ll long long 
using namespace std;
const int maxn=3e6+101;
const int MOD=998244353;
const int inf=2147483647;
int read(){
    int x=0,f=1;char ch=getchar();
    for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
    for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';
    return x*f;
}
int n,m;
int tot,head[maxn],nx[maxn],to[maxn];
void add(int x,int y){to[++tot]=y;nx[tot]=head[x];head[x]=tot;}
int dfn[maxn],co[maxn],cnt,st[maxn],top,low[maxn],sum;
void tarjan(int u){
    low[u]=dfn[u]=++sum;
    st[++top]=u;
    for(int i=head[u];i;i=nx[i]){
        int k=to[i];
        if(!dfn[k]){
            tarjan(k);
            low[u]=min(low[u],low[k]);
        }
        else if(!co[k])low[u]=min(low[u],dfn[k]);
    }
    if(low[u]==dfn[u]){++cnt;while(!co[u]){co[st[top--]]=cnt;}}
    return ;
}
int main(){
    n=read();m=read();
    for(int i=1;i<=m;i++){
        int x=read(),y=read();
        int xx,yy;
        if(x&1)xx=x+1;
        else xx=x-1;
        if(y&1)yy=y+1;
        else yy=y-1;
        add(x,yy);add(y,xx);
    }
    for(int i=1;i<=n*2;i++){if(!dfn[i])tarjan(i);}
    for(int i=1;i<=n;i+=2){
        if(co[i]==co[i+1]){printf("NIE");return 0;}
    }
    for(int i=1;i<=n*2;i+=2){
        if(co[i]<co[i+1])printf("%d\n",i);
        else printf("%d\n",i+1);
    }
    return 0;
}
posted @ 2021-12-06 18:23  I_N_V  阅读(41)  评论(0编辑  收藏  举报