[CF776D] The Door Problem

Description

每扇门被两个开关控制,操作一个开关将改变所有它所控制的门的状态。求是否存在一个操作方案,打开所有的门。

Solution

对于开关设状态,(1) 表示操作这个开关,(0) 表示不操作

如果一扇门的状态是 (1),则控制它的两个开关状态必须相同((00/11)

如果一扇门的状态是 (0),则控制它的两个开关状态必须相反((01/10)


回顾一下 2-SAT 的建图方法

设有 (n)(x_i),逻辑约束为一个主合取范式

每条边 (p o q) 表示选了 (p) 就必须要选 (q)

因此例如对于 (i or j),我们连边 ( eg i o j) 以及 ( eg j o i)

考虑每个变量

如果 (x o eg x),则 (x=0);如果 ( eg x o x),则 (x=1);如果 (x o eg x and eg x o x) 则无解

因此,如果任意一个变量 (x)( eg x) 在同一个 SCC 中,则无解,跑一遍 Tarjan 即可


回到本题,设某门对应的开关是 (p,q)

如果门是 (1),则 (p o q, q o p, eg p o eg q, eg q o eg p)

如果门是 (0),则 (p o eg q, q o eg p, eg p o q, eg q o p)

#include <bits/stdc++.h>
using namespace std;

#define int long long
const int N = 200005;

namespace scc
{
vector <int> g[N],scc[N];
int ind,f[N],siz[N],dfn[N],low[N],vis[N],s[N],bel[N],top,tot,n,m,d[N];
char ch[N];
void make(int p,int q)
{
    d[q]++;
    g[p].push_back(q);
}
void dfs(int p)
{
    s[++top]=p;
    dfn[p]=low[p]=++ind;
    for(int i=0; i<g[p].size(); i++)
    {
        int q=g[p][i];
        if(!dfn[q]) dfs(q), low[p]=min(low[p],low[q]);
        else if(!bel[q]) low[p]=min(low[p],dfn[q]);
    }
    if(dfn[p]==low[p])
    {
        ++tot;
        for(int i=0; i!=p;)
        {
            i=s[top--];
            bel[i]=tot;
            scc[tot].push_back(i);
        }
    }
}
void solve(int _n)
{
    n=_n;
    for(int i=1; i<=n; i++) if(!dfn[i]) dfs(i);
}
bool getans()
{
    for(int i=1;i<=n/2;i++)
    {
        if(bel[i]==bel[i+n/2]) return false;
    }
    return true;
}
}

using scc::make;

int n,m,r[N],p[N],q[N],t,k;

signed main()
{
    ios::sync_with_stdio(false);
    cin>>n>>m;
    for(int i=1;i<=n;i++)
    {
        cin>>r[i];
    }
    for(int i=1;i<=m;i++)
    {
        cin>>t;
        while(t--)
        {
            cin>>k;
            if(p[k]==0) p[k]=i;
            else q[k]=i;
        }
    }
    for(int i=1;i<=n;i++)
    {
        if(r[i])
        {
            make(p[i],q[i]);
            make(q[i],p[i]);
            make(p[i]+m,q[i]+m);
            make(q[i]+m,p[i]+m);
        }
        else
        {
            make(p[i],q[i]+m);
            make(q[i],p[i]+m);
            make(p[i]+m,q[i]);
            make(q[i]+m,p[i]);
        }
    }
    scc::solve(2*m);
    cout<<(scc::getans()?"YES":"NO")<<endl;
}

原文地址:https://www.cnblogs.com/mollnn/p/13237638.html