题目链接:https://codeforces.com/contest/776/problem/D
题目大意:有n扇门,刚开始有的开着有的关着,有m个开关可同时改变多个门的状态,问是否能通过这些开关是所有门同时打开。
题目思路:
并查集做法:由于题目有个限制条件是一扇门最多被两个开关控制,所以可以用并查集。将按钮没按作为前m个,按了作为后m个,那么当门之前是开着的时候,控制它的按钮要么都被按了,要么都没被按,将a,b和a+m,b+m合并。而对于关着的门,至少其中一个被按了,将a,b+m和a+m,b合并,最后判断是否存在i和i+m在同一个并查集中即可。
2-SAT做法:思路完全相同,把合并改成建边即可。
以下是代码:
并查集:
#include<bits/stdc++.h>
using namespace std;
#define inf 0x3f3f3f3f
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define per(i,a,b) for(int i=a;i>=b;i--)
#define ll long long
const int MAXN = 2e6+5;
int n,m,r[MAXN],x,y,pre[MAXN];
vector<int>v[MAXN];
int Find(int x){
return x==pre[x]?x:pre[x]=Find(pre[x]);
}
int main(){
while(~scanf("%d%d",&n,&m)){
rep(i,1,n){
scanf("%d",&r[i]);
v[i].clear();
}
rep(i,1,m){
scanf("%d",&x);
rep(j,1,x){
scanf("%d",&y);
v[y].push_back(i);
}
}
rep(i,1,2*m){
pre[i]=i;
}
rep(i,1,n){
x=v[i][0],y=v[i][1];
if(r[i]){
pre[Find(x)]=Find(y);
pre[Find(x+m)]=Find(y+m);
}
else{
pre[Find(x)]=Find(y+m);
pre[Find(x+m)]=Find(y);
}
}
int flag=0;
rep(i,1,m){
if(Find(i)==Find(i+m)){
flag=1;
break;
}
}
if(flag)puts("NO");
else puts("YES");
}
return 0;
}
2-SAT:
#include<bits/stdc++.h>
using namespace std;
#define inf 0x3f3f3f3f
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define per(i,a,b) for(int i=a;i>=b;i--)
#define ll long long
const int MAXN = 2e6+5;
int x,y,n,m,dfn[MAXN],low[MAXN],vis[MAXN],ans,tot,num,belong[MAXN],a,b;
vector<int>g[MAXN],v[MAXN];
stack<int>s;
void tarjan(int u){
low[u]=dfn[u]=++tot;
s.push(u);
vis[u]=1;
int len=g[u].size();
rep(i,0,len-1){
int v=g[u][i];
if(!dfn[v])tarjan(v),low[u]=min(low[u],low[v]);
else if(vis[v])low[u]=min(low[u],dfn[v]);
}
if(low[u]==dfn[u]){
num++;
while(1){
int now=s.top();
s.pop();
belong[now]=num;
vis[now]=0;
if(now==u)break;
}
}
}
int r[MAXN];
int main(){
while(~scanf("%d%d",&n,&m)){
tot=0;
ans=0;
num=0;
rep(i,1,n){
scanf("%d",&r[i]);
v[i].clear();
}
while(!s.empty())s.pop();
memset(dfn,0,sizeof(dfn));
memset(low,0,sizeof(low));
memset(vis,0,sizeof(vis));
memset(belong,0,sizeof(belong));
rep(i,1,2*m)g[i].clear();
rep(i,1,m){
scanf("%d",&x);
rep(j,1,x){
scanf("%d",&y);
v[y].push_back(i);
}
}
rep(i,1,n){
x=v[i][0],y=v[i][1];
if(r[i]){
g[x].push_back(y);
g[x+m].push_back(y+m);
g[y].push_back(x);
g[y+m].push_back(x+m);
}
else{
g[x].push_back(y+m);
g[x+m].push_back(y);
g[y].push_back(x+m);
g[y+m].push_back(x);
}
}
rep(i,1,2*m){
if(!dfn[i]){
tarjan(i);
}
}
int flag=0;
rep(i,1,m){
if(belong[i]==belong[i+m]){
flag=1;
break;
}
}
if(flag)puts("NO");
else{
puts("YES");
}
}
return 0;
}