2-SAT

前置芝士:强连通分量。

先放一个板子题:2-SAT

我们先考虑拆点,把每个变量 i 拆成两个点,i×2i×2+1,前一个代表这个变量 i 取假,后一个代表这个变量 i 取真。

既然有了点,我们就要考虑连边。例如给一个条件:11 或者 30。我们就要建两条边,一条为如果 1030,即 26;另一条为如果 3111,即 73

然后看一下这条边表示什么,表示的是一个要求是另一个要求的充分条件(建议学习一下充分条件与必要条件)。

那么,如果发现图中出现了 i 真是 i 假的充分条件;i 假是 i 真的充分条件,那么一定无解,因为不管 i 取什么,条件1总会要求你取 i 当前的值取反,这显然不可能成立。

换句话说,就是 i[1,n] 如果 i×2i×2+1 在一个强连通分量中,一定无解,否则有解。

说了这么多,我们终于说完了怎么判断有没有解,接下来说一下怎么构造解。

首先我们记 idi 表示图中的 i 号点所在的强连通分量的编号。根据上面的描述,如果 i[1,n],idi×2=idi×2+1,无解。

否则这两个东西的 id 数组,一定一个大一个小(废话)。

那么,id 更小的那一部分可以认为是另一部分的上司(不同于寻常意义),换句话说它具有决定权,变量的值就取决于他。

这是一个小结论,证明的话建议看一些其他资料,这里建议记住,遇到的时候直接用就可以了。

下面放一下板子题的代码:

#include<bits/stdc++.h>
#define int long long
#define N 2000005
#define M 2000005
using namespace std;
int n,m,h[N],e[M],ne[M],idx,dfn[N],low[N],ts,stk[N],top,id[N],cnt;
bool ins[N];
void add(int a,int b){//链式前向星建边 
    e[idx]=b;
    ne[idx]=h[a];
    h[a]=idx++;
}
void tar(int u){//经典tarjan求强连通分量 
    dfn[u]=low[u]=++ts;
    stk[++top]=u;
    ins[u]=1;
    for(int i=h[u];~i;i=ne[i]){
        int j=e[i];
        if(!dfn[j]){
            tar(j);
            low[u]=min(low[u],low[j]);
        }
        else if(ins[j])low[u]=min(low[u],dfn[j]);
    }
    if(low[u]==dfn[u]){
        int y;
        cnt++;
        do{
            y=stk[top--];
            ins[y]=0;
            id[y]=cnt;
        }while(y!=u);
    }
}
signed main(){
    cin>>n>>m;
    memset(h,-1,sizeof h);
    while(m--){
        int i,a,j,b;
        cin>>i>>a>>j>>b;
        i--;j--;
        add(2*i+!a,2*j+b);//按照上面说的充分条件的方式建边 
        add(2*j+!b,2*i+a);
    }
    for(int i=0;i<n*2;i++){
        if(!dfn[i]){//tarjan 
            tar(i);
        }
    }
    for(int i=0;i<n;i++){
        if(id[i*2]==id[i*2+1]){//互为充分条件则无解 
            cout<<"IMPOSSIBLE";
            return 0;
        }
    }
    cout<<"POSSIBLE\n";//否则有解 
    for(int i=0;i<n;i++){
        if(id[i*2]<id[i*2+1]){//"上司"具有最终决定权 
            cout<<"1 ";
        }
        else cout<<"0 ";
    }
    return 0;
}

再来一个稍微困难的题:满汉全席

先把原题面进行转化,发现对于每个评审员要满足两个要求的至少一个。所以可以认为 m 代表假,h 代表真,这就转化成了上一道板子题。

我们对 mh 进行分类讨论,每个要求建 2 条边,最后判断代表一个变量的两个点在不在一个强连通分量中即可。

这里把这道题进行略微强化,请读者思考如果 2 个要求能且仅能满足 1 个该如何做。

posted @   zxh923  阅读(7)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示