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 }