• [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;
    }
    
    
  • 相关阅读:
    git或gitee 提交代码到远程仓库
    gitee 创建代码仓库,并提交本地代码
    Logback 实现日志链路追踪
    navicat 查看,设计并导出数据库 ER图
    Jackson 使用 @JsonFormat 注解进行时间格式化
    Redis 缓存常见问题
    jedis 与 redission 实现分布式锁
    Redis 集群模式搭建
    Redis 哨兵模式高可用
    Notepad++ 正则表达式提取信息
  • 原文地址:https://www.cnblogs.com/mollnn/p/13237638.html
Copyright © 2020-2023  润新知