Codeforces 776D.The Door Problem (dfs二分图判定 / 并查集)
Posted tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Codeforces 776D.The Door Problem (dfs二分图判定 / 并查集)相关的知识,希望对你有一定的参考价值。
题目链接:
http://codeforces.com/problemset/problem/776/D
题意:
n扇门,m个开关(n,m<=1e5),每个开关控制若干个门,反转开关门状态变化,每个门正好被两个开关控制,问是否有可能把所有门的状态置为1?
思路:
from: http://blog.csdn.net/jeremy1149/article/details/56839453
方法一:二分图染色
注意到一个门只被两个开关控制 若门初始为0 则控制它的两个开关状态相反,门初始为1则 要求控制的两个开关状态相同,才能可以把门置为1.
以开关为顶点,(u,v)的边为被(u,v)控制的门的初始状态, dfs做二分图染色,判断每条边(每扇门)是否都能被满足
方法二:并查集
把每一个钥匙拆成两个点x,x+m,分别表示选不选这把钥匙。
我们知道一扇门一定对应了两把钥匙。
设一扇门对应的要是分别为u,v,link(x,y)表示点x向点y连边。
如果这扇门要操作一次,那就是两把当中选一把:link(u,v+m),link(v,u+m)。这表示的是如果我选了拿第u把钥匙就不能拿第v把钥匙,如果我选了拿第v把钥匙就不能拿第u把钥匙
如果这扇门不要操作,那就是两把当中选两把或者都不选:link(u+m,v+m),link(v,u)。这表示的是如果我选了拿第u把钥匙就一定要拿第v把钥匙,如果我不拿第v把钥匙就一定不能拿第u把钥匙
这个是无向边啊,并查集维护一下关系即可。
对于1...m中的每一把钥匙,如果x,x+m属于一个连通块就无解了,因为包含关系成环。
代码:
代码一:
#include<bits/stdc++.h> using namespace std; typedef long long ll; #define MS(a) memset(a,0,sizeof(a)) #define MP make_pair #define PB push_back const int INF = 0x3f3f3f3f; const ll INFLL = 0x3f3f3f3f3f3f3f3fLL; inline ll read(){ ll x=0,f=1;char ch=getchar(); while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();} while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();} return x*f; } ////////////////////////////////////////////////////////////////////////// const int maxn = 1e5+10; int n,k,st[maxn],c[maxn],flag; vector<int> p[maxn]; vector<pair<int,int> > g[maxn]; void dfs(int u,int x){ if(flag == false) return ; if(c[u] != -1){ if(c[u] != x) flag=false; return ; } c[u] = x; for(int i=0; i<(int)g[u].size(); i++){ int v = g[u][i].first, w = g[u][i].second; int y; if(w == 1) y = x; else y = x^1; dfs(v,y); } } int main(){ cin >> n >> k; for(int i=1; i<=n; i++) st[i] = read(); for(int i=1; i<=k; i++){ int num = read(); while(num--){ int x = read(); p[x].push_back(i); } } for(int i=1; i<=n; i++){ int u = p[i][0], v = p[i][1]; g[u].push_back(MP(v,st[i])); g[v].push_back(MP(u,st[i])); } flag = 1; memset(c,-1,sizeof(c)); for(int i=1; i<=k; i++){ if(c[i] == -1) dfs(i,0); } if(flag) puts("YES"); else puts("NO"); return 0; }
代码二:
#include<bits/stdc++.h> using namespace std; typedef long long ll; #define MS(a) memset(a,0,sizeof(a)) #define MP make_pair #define PB push_back const int INF = 0x3f3f3f3f; const ll INFLL = 0x3f3f3f3f3f3f3f3fLL; inline ll read(){ ll x=0,f=1;char ch=getchar(); while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();} while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();} return x*f; } ////////////////////////////////////////////////////////////////////////// const int maxn = 2e5+10; int n,k,st[maxn],fa[maxn]; vector<int> p[maxn]; int find(int x){ return fa[x]==x ? x : fa[x]=find(fa[x]); } void merge(int u,int v){ int p1 = find(u), p2 = find(v); if(p1==p2) return ; fa[p1] = p2; } int main(){ cin >> n >> k; for(int i=1; i<=n; i++) st[i] = read(); for(int i=1; i<=k; i++){ int num = read(); for(int j=0; j<num; j++){ int x = read(); p[x].push_back(i); } } for(int i=1; i<=2*k; i++) fa[i]=i; for(int i=1; i<=n; i++){ int u = p[i][0], v = p[i][1]; if(st[i]){ merge(u,v); merge(u+k,v+k); }else{ merge(u,v+k); merge(u+k,v); } } for(int i=1; i<=k; i++){ if(find(i) == find(i+k)){ puts("NO"); return 0; } } puts("YES"); return 0; }
以上是关于Codeforces 776D.The Door Problem (dfs二分图判定 / 并查集)的主要内容,如果未能解决你的问题,请参考以下文章
Codeforces 776D:The Door Problem(DFS染色)
CodeForces 776D The Door Problem并查集