Codeforces 776D:The Door Problem

Codeforces 776D:The Door Problem

题目链接:http://codeforces.com/problemset/problem/776/D

题目大意:有n扇门及m个开关,每扇门由两个开关控制,初始状态为1(unlocked)或者0(locked)。每个开关控制xi扇门,若选择了当前开关,那么该开关所控制的所有门的状态取反(1变成0,0变成1)。问能否是所有门的状态全部为1.

并查集

将每个开关拆分成两个点:选择和不选择(对应x和x+m).

每扇门对应两个开关u和v,若初始状态为1,则需要同时选择两个开关(u,v)或者同时不选择两个开关(u+m,v+m);

若初始状态为0,则仅可以选择一个开关(u,v+m)或者(u+m,v).

将门作为边按上面描述连接两个开关(这样保证了每扇门的最终状态均为1),形成的连通块(连通块表示被限制在一起的开关)中若同时存在x与x+m,则无解.

代码如下:

 1 #include <cstdio>
 2 #include <iostream>
 3 #define N 100005
 4 using namespace std;
 5 int n,m,d[N],sd[N][3],f[2*N];
 6 int Find(int x){
 7     return f[x]==x?x:f[x]=Find(f[x]);
 8 }
 9 void link(int a,int b){
10     int x=Find(a),y=Find(b);
11     if(x!=y)f[x]=y;
12 }
13 int main(void){
14     cin>>n>>m;
15     for(int i=0;i<n;++i)cin>>d[i];
16     for(int i=0;i<m;++i){
17         int x;
18         cin>>x;
19         for(int j=0;j<x;++j){
20             int dr;
21             cin>>dr;dr--;
22             sd[dr][++sd[dr][0]]=i;
23         }
24     }
25     for(int i=0;i<2*m;++i)f[i]=i;
26     for(int i=0;i<n;++i){
27         if(d[i])link(sd[i][1],sd[i][2]),link(sd[i][1]+m,sd[i][2]+m);
28         else link(sd[i][1],sd[i][2]+m),link(sd[i][1]+m,sd[i][2]);
29     }
30     for(int i=0;i<m;++i)
31     if(Find(i)==Find(i+m)){
32         cout<<"NO";
33         return 0;
34     }
35     cout<<"YES";
36 }

 

posted @ 2017-02-24 16:24  barriery  阅读(544)  评论(0编辑  收藏  举报