Codeforces 776D.The Door Problem (dfs二分圖判定 / 並查集)
阿新 • • 發佈:2017-07-27
二分圖染色 space find inline lin rem amp 屬於 兩個
題目鏈接:
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二分圖判定 / 並查集)