首页 > 代码库 > Codeforces 776D:The Door Problem(DFS染色)

Codeforces 776D:The Door Problem(DFS染色)

http://codeforces.com/problemset/problem/776/D

题意:有n个门,m个开关,每个门有一个当前的状态(0表示关闭,1表示打开),每个开关控制k个门,但是每个门确切的受两个开关控制,如果一个开关打开,那么原来关闭的门会打开,打开的门关闭,问是否存在一个情况使得所有的门打开。

思路:类似于01染色,把开关当成点,门当前的状态当成边权建图。初始先假设一个门的状态(初始假设为0和假设为1都是一样的,举几个例子就发现了),然后因为每个门受两个开关控制,所以可以推出下一个门的状态,如果发现互斥的情况,那么就是“NO”。

这里设成门状态0表示打开,1表示关闭,方便运算。

 1 #include <bits/stdc++.h> 2 using namespace std; 3 #define N 200010 4 struct Edge { 5     int v, nxt, w; 6 } edge[N*2]; 7 int col[N], fir[N], sec[N], head[N], tot, w[N]; 8  9 void Add(int u, int v, int w) {10     edge[tot] = (Edge) {v, head[u], w}; head[u] = tot++;11     edge[tot] = (Edge) {u, head[v], w}; head[v] = tot++;12 }13 14 bool dfs(int u) {15     for(int i = head[u]; ~i; i = edge[i].nxt) {16         int v = edge[i].v, w = edge[i].w;17         if(col[v] == -1) { // 如果这个开关没染色18             col[v] = col[u] ^ w;19             if(!dfs(v)) return false;20         } else if(col[u] ^ col[v] ^ w) return false; // 如果染过色并发生矛盾21     }22     return true;23 }24 25 int main() {26     int n, m;27     cin >> n >> m;28     for(int i = 1; i <= n; i++) scanf("%d", &w[i]), w[i] ^= 1;29     for(int i = 1; i <= m; i++) {30         int k; scanf("%d", &k);31         while(k--) {32             int a; scanf("%d", &a);33             if(fir[a] == 0) fir[a] = i; // 连a点的第一个开关34             else sec[a] = i; // 连a点的第二个开关35         }36     }37     memset(head, -1, sizeof(head)); tot = 0;38     for(int i = 1; i <= n; i++)39         Add(fir[i], sec[i], w[i]);40     memset(col, -1, sizeof(col));41     bool flag = 1;42     for(int i = 1; i <= m; i++) {43         if(col[i] == -1) {44             col[i] = 0; // 假设这个开关一开始是关的45             if(!dfs(i)) { flag = 0; break; }46         }47     }48     if(!flag) puts("NO");49     else puts("YES");50     return 0;51 }

 

Codeforces 776D:The Door Problem(DFS染色)