CodeForces 776D The Door Problem【并查集】

CodeForces 776D The Door Problem【并查集】
并查集
设 f 1--m 表示 开的情况 m+1--2*m 表示关的情况
对于每盏灯
如果他 是关的 则 x--y x+m--y+m 表示要同关 或者同开
如果他 是开的 则 x+m--y x--y+m 表示一个关 一个开
如果一盏灯 的 x 连向 了 x+m 则表示是矛盾了 那么久是错误的

题意:给你n个门,和m组开关,每扇门都有两个开关控制,每个开关控制x扇门,
如果选择了某组开关,则使这组开关里的每个开关控制的所有的门按状态取反,
问你是否能使得所有的门状态为1
解析:将每个开关拆分成两个点,选这个开关和不选这个开关(x,x+m),根据每扇门的状态来,
如果状态为1,则需要同时选择这两个开关或者不选,如果状态为零,那么只能选择一个开关。
根据上面的情况做并查集,然后判断第i(选)组开关和i+m(选)是否联通,有则无解

 1 #include <cstdio>
 2 using namespace std ; 
 3 
 4 const int maxn = 100011 ; 
 5 int n,m,k ; 
 6 int light[ maxn ],g[maxn][3],f[maxn*2] ; 
 7 
 8 inline int getfather(int x) 
 9 {
10     if(x==f[x]) return x ; 
11     f[x] = getfather(f[x]) ; 
12     return f[x] ; 
13 }
14 
15 inline void merge(int x,int y) 
16 {
17     int xx,yy ; 
18     xx = getfather(x) ;   yy = getfather(y) ; 
19     if(xx!=yy) f[xx] = yy ;  
20 }
21 
22 int main() 
23 {
24     scanf("%d%d",&n,&m) ;    
25     for(int i=1;i<=n;i++) 
26         scanf("%d",&light[ i ]) ; 
27     int x,y ; 
28     for(int i=1;i<=m;i++) 
29     {
30         scanf("%d",&k) ; 
31         for(int j=1;j<=k;j++) 
32             scanf("%d",&x) , g[x][++g[x][0]] = i ;  
33     }
34     
35     for(int i=1;i<=2*m;i++) f[ i ] = i ; 
36     for(int i=1;i<=n;i++) 
37     {
38         x = g[i][1] ; 
39         y = g[i][2] ; 
40         if(light[ i ]) 
41         {
42             merge(x,y) ; 
43             merge(x+m,y+m) ; 
44         }
45         else
46         {
47             merge(x,y+m) ; 
48             merge(y,x+m) ; 
49         }
50     }
51     
52     bool flag = 0 ;
53     int xx,yy ;  
54     for(int i=1;i<=m;i++) 
55     {
56         xx = getfather( i ) ; 
57         yy = getfather( i+m ) ;  
58         if(xx==yy) flag = 1 ; 
59     }
60     if(flag) 
61         printf("NO
") ; 
62     else 
63         printf("YES
") ; 
64     return 0 ; 
65 }
原文地址:https://www.cnblogs.com/third2333/p/7111280.html