题目描述:
有n个房子 起始时有的开有的关, 有m个开关每个开关控制几个房间(改变一次全部房子的状态就改变 原来开(开->关)或者 原来 关(关->开)),但一个房间恰好由两个开关控制
问能否同时打开n个房子
2 ≤ n ≤ 10^5, 2 ≤ m ≤ 10^5
分析:
假如不能同时打开n个房子 那么比会有一个开关同时出现打开和关闭,所以将开关的情况都放在一颗树上 比如:两个开关x,y 如果对应的门关则 x开,y不开,或则y开,x不开 当问打开时也有相同的道理
如果同一个开关 开或不开同时出现在了一棵树上则不能同时打开全部门;
显然这种方法是用并查集搜索,注意查完以后立刻更新该点指向的根节点,否则会超时
ac代码:
#include<bits/stdc++.h> using namespace std; const int MAX=1e5+2; int switch1[MAX*2]; vector<int> door[MAX]; int find(int x){ if(switch1[x]==x)return x; else return switch1[x]=find(switch1[x]); } void merge(int a,int b){ int x=find(a),y=find(b); if(x!=y) switch1[x]=y; } int main(){ ios::sync_with_stdio(0); cin.tie(0); int n,m; int vis[MAX]; cin>>n>>m; for(int i=1;i<=n;i++) cin>>vis[i]; for(int i=1;i<=2*m;i++)switch1[i]=i; for(int i=1;i<=m;i++){ int number; cin>>number; for(int j=1;j<=number;j++){ int door1; cin>>door1; door[door1].push_back(i); } } for(int i=1;i<=n;i++){ int swi1=door[i][0],swi2=door[i][1]; if(!vis[i]){ merge(swi1,swi2+m);//加个m表示关 merge(swi1+m,swi2); } else{ merge(swi1,swi2); merge(swi1+m,swi2+m); } } int flag=0; for(int i=1;i<=m;i++) if(find(i+m)==find(i)) { flag=1; break ; } // } flag==1?puts("NO"):puts("YES"); }