Codeforces 776D【The Door Problem】(2-SAT)

难度CF2000分

题意:给你n个门,m把锁。每个门由2把锁控制,给你每个门的初始状态以及每把锁可以控制的t个门,问你能否使用锁将这些门全部打开。0是关闭,1是开启。

题解:因为很久没使用2-sat导致自己一开始不会做这个题,然后看了题解才恍然大悟。我们这么来想:因为每个门只能被2把钥匙控制,如果门初始的状态是0,那么也就是控制该门的2个钥匙只有1个钥匙生效;如果门的状态是1,那么就是控制该门的2个钥匙都生效或者都不生效。那么我们就可以将其转化为2-sat模型。生效为2*i,不生效为2*i+1。然后进行建边操作,最后跑tarjan看是否有id[2*i]==id[2*i+1]的情况,如果有的话说明不行,输出NO,反之输出YES

#include<bits/stdc++.h>
#pragma GCC optimize(2)
#define ll long long
#define rep(i,a,n) for(int i=a;i<=n;i++)
#define per(i,n,a) for(int i=n;i>=a;i--)
#define endl '
'
#define eps 0.000000001
#define pb push_back
#define mem(a,b) memset(a,b,sizeof(a))
#define IO ios::sync_with_stdio(false);cin.tie(0);
using namespace std;
const int INF=0x3f3f3f3f;
const ll inf=0x3f3f3f3f3f3f3f3f;
const int mod=1e9+7;
const int maxn=2e5+5;
int tot,head[maxn];
struct E{
    int to,next;
}edge[maxn<<1];
void add(int u,int v){
    edge[tot].to=v;
    edge[tot].next=head[u];
    head[u]=tot++;
}
int dfn[maxn],low[maxn],id[maxn],vis[maxn],cnt,tott;
stack<int> s;
void tarjan(int x){
    dfn[x]=low[x]=++tott;
    s.push(x);vis[x]=1;
    for(int i=head[x];i!=-1;i=edge[i].next){
        int v=edge[i].to;
        if(!dfn[v]){
            tarjan(v);
            low[x]=min(low[x],low[v]);
        }
        else if(vis[v]){
            low[x]=min(low[x],dfn[v]);
        }
    }
    if(low[x]==dfn[x]){
        ++cnt;
        while(1){
            int now=s.top();s.pop();
            id[now]=cnt;
            vis[now]=0;
            if(x==now) break;
        }
    }
}
int n,m,a[maxn];
vector<int> w[maxn];
int main(){
    scanf("%d%d",&n,&m);mem(head,-1);
    rep(i,1,n) scanf("%d",&a[i]);
    rep(i,1,m){
        int t;scanf("%d",&t);
        while(t--){
            int x;scanf("%d",&x);
            w[x].push_back(i);
        }
    }
    rep(i,1,n){
        int x=w[i][0],y=w[i][1];
        x*=2;y*=2;
        if(a[i]==0){
            add(x,y+1);add(y+1,x);
            add(x+1,y);add(y,x+1);
        }else{
            add(x,y);add(y,x);
            add(x+1,y+1);add(y+1,x+1);
        }
    }
    rep(i,2,2*m+1){
        if(!dfn[i]) tarjan(i);
    }
    for(int i=1;i<=m;i++){
        if(id[i*2]==id[i*2+1]){
            puts("NO");return 0;
        }
    }
    puts("YES");
}
View Code
原文地址:https://www.cnblogs.com/Anonytt/p/13863942.html