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\n") ; 62 else 63 printf("YES\n") ; 64 return 0 ; 65 }
时间: 2024-11-03 21:25:50