题目描述:
有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");
}

京公网安备 11010502036488号