• CodeForces-776D The Door Problem(2-SAT)


    题意:有n间房间,一些房间是上锁的,一些是未上锁的,只有所有门未上锁的时候,所有人才能逃出去,这里有m个开关,每个开关都可以控制多扇门,一旦按下一个开关,控制的门的状态都会发生变化,未上锁的变成上锁,上锁的变成未上锁。求是否存在一种情况使得所有的门都未上锁。

    分析:题目中给出了暗示,说每个门只被两个开关控制。
    我们考虑门的初始状态,如果是未上锁的,我们要保持它的未上锁状态。
    我们假定开关按下为1,开关没按下为2。按两次等价于没按。
    如果门未上锁,那么按下了第一个开关,第二个开关也要按下,
    它的逆否命题也要添加进去,连一条边,第二个开关没按,那么第一个开关也不能按。
    如果第一个开关没按,第二个开关也不能按,
    它的逆否命题如果第二个开关按了,第一个开关也要按下。
    总共四种情况,连4条边。

    上锁的状态我们要变成未上锁,这个同理。

    然后用tarjan求有向图的强连通分量算法求出是否存在一个开关既要开,又要关的情况。如果存在,输出NO。

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <vector>
    #include <algorithm>
    
    using namespace std;
    const int N = 100005;
    int r[N];//门的初始状态
    vector<int> a[N];
    int h[2 * N], e[8 * N], ne[8 * N], idx;
    
    void add(int a, int b)
    {
    	e[idx] = b, ne[idx] = h[a], h[a] = idx++;
    }
    
    int dfn[2 * N], low[2 * N], timestamp;
    int stk[2 * N], in_stk[2 * N], top;
    int scc_cnt;
    int id[2 * N];
    int sz[2 * N];
    
    void tarjan(int u)
    {
    	dfn[u] = low[u] = ++timestamp;
    	stk[++top] = u, in_stk[u] = true;
    	for (int i = h[u]; i != -1; i = ne[i])
    	{
    		int j = e[i];
    		if (!dfn[j])
    		{
    			tarjan(j);
    			low[u] = min(low[u], low[j]);
    		}
    		else if (in_stk[j])
    			low[u] = min(low[u], dfn[j]);
    	}
    	if (dfn[u] == low[u])
    	{
    		int y;
    		++scc_cnt;
    		do {
    			y = stk[top--];
    			in_stk[y] = false;
    			id[y] = scc_cnt;
    			++sz[scc_cnt];
    		} while (y != u);
    	}
    }
    
    int main()
    {
    	//rooms switches
    	int n, m;
    	scanf("%d%d", &n, &m);
    
    	for (int i = 1; i <= n; ++i)
    		scanf("%d", &r[i]);//门的状态
    
    	//m个开关
    	int d, q;
    	for (int i = 1; i <= m; ++i)
    	{
    		//控制的门数量
    		scanf("%d", &d);
    		for (int j = 1; j <= d; ++j)
    		{
    			scanf("%d", &q);
    			a[q].push_back(i);//控制门的开关
    		}
    	}
    	
    	memset(h, -1, sizeof h);
    	for (int i = 1; i <= n; ++i)
    	{
    		if (r[i])//门未锁
    		{
    			add(a[i][0] + m, a[i][1] + m);
    			add(a[i][1], a[i][0]);
    			add(a[i][0], a[i][1]);
    			add(a[i][1] + m, a[i][0] + m);
    		}
    		else//锁了
    		{
    			add(a[i][0] + m, a[i][1]);
    			add(a[i][1] + m, a[i][0]);
    			add(a[i][0], a[i][1] + m);
    			add(a[i][1], a[i][0] + m);
    		}
    	}
    	
    	for (int i = 1; i <= 2 * m; ++i)
    	{
    		if (!dfn[i])
    		{
    			tarjan(i);
    		}
    	}
    	
    	bool flag = true;
    	for (int i = 1; i <= m; ++i)
    	{
    		if (id[i] == id[i + m])
    		{
    			flag = false;
    		}
    	}
    
    	if (flag)
    	{
    		puts("YES");
    	}
    	else
    	{
    		puts("NO");
    	}
    
    	return 0;
    }
    
  • 相关阅读:
    微服务全链路剖析
    记一次被挖矿经历
    centos权限总结
    Beizer。。。。。
    遇到的几个算法
    程序截图
    CFileViewer(文件浏览器)
    框架设计
    git常用代码
    右值引用
  • 原文地址:https://www.cnblogs.com/pixel-Teee/p/12778946.html
Copyright © 2020-2023  润新知