Codeforces 776D - The Door Problem (2-SAT)
参考博客
补题链接
这个题太妙啦。2-SAT和两个状态有关,但是显然如果考虑门的开和关那基本没什么思路,因为两个门基本相互独立。但是如果考虑🔑的使用(1)还是不使用(0)两个状态会发现,两个🔑直接还是有一些相互限制的要求的。比如本题要所以门都变成1,且每个门有两个🔑,所以如果原来门是1的那么它对应的两个🔑要么都使用,要么都不使用。如果门的状态是0,那么两个🔑只能用一个。
两个点状态相同连边:
\(a -> b, b - > a, a' -> b', b' -> a'\)
两个点状态不同连边:
\(a -> b', b -> a', a' -> b, b' -> a\)
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<map>
#include<queue>
#include<vector>
#include<string>
#include<fstream>
using namespace std;
#define rep(i, a, n) for(int i = a; i <= n; ++ i);
#define per(i, a, n) for(int i = n; i >= a; -- i);
typedef long long ll;
const int N = 2e5 + 105;
const int mod = 1e9 + 7;
const double Pi = acos(- 1.0);
const ll INF = 1e18;
const int G = 3, Gi = 332748118;
ll qpow(ll a, ll b) { ll res = 1; while(b){ if(b & 1) res = (res * a) % mod; a = (a * a) % mod; b >>= 1;} return res; }
ll gcd(ll a, ll b) { return b ? gcd(b, a % b) : a; }
// bool cmp(int a, int b){return a > b;}
//
int n, m;
int head[N], cnt = 0;
int low[N], dfn[N], Stack[N], Belong[N];
int Index, top, scc;
bool Instack[N];
int to[N << 1], nxt[N << 1];
int tx[N], ty[N], a[N];
void add(int u, int v){
to[cnt] = v, nxt[cnt] = head[u], head[u] = cnt ++;
}
void Tarjan(int u){
int v;
low[u] = dfn[u] = ++ Index;
Stack[top ++] = u;
Instack[u] = true;
for(int i = head[u]; i != -1; i = nxt[i]){
v = to[i];
if(!dfn[v]){
Tarjan(v);
if(low[u] > low[v] ) low[u] = low[v];
}
else if(Instack[v] && low[u] > dfn[v]) low[u] = dfn[v];
}
if(low[u] == dfn[u]){
scc ++;
do{
v = Stack[-- top];
Instack[v] = false;
Belong[v] = scc;
}while(v != u);
}
}
void solve(){
memset(dfn,0,sizeof(dfn));
memset(Instack,false,sizeof(Instack));
Index = top = scc = 0;
for(int i = 1; i <= m * 2; ++ i)
if(!dfn[i])
Tarjan(i);
}
void init(){
cnt = 0;
memset(head,-1,sizeof(head));
}
int main()
{
scanf("%d%d",&n,&m);
for(int i = 1; i <= n; ++ i) scanf("%d",&a[i]);
init();
for(int i = 1; i <= m; ++ i){
int k; scanf("%d",&k);
while(k --){
int x; scanf("%d",&x);
if(!tx[x]) tx[x] = i;
else ty[x] = i;
}
}
for(int i = 1; i <= n; ++ i){
if(a[i]){
add(tx[i], ty[i]), add(ty[i], tx[i]);
add(tx[i] + m, ty[i] + m), add(ty[i] + m, tx[i] + m);
}
else{
add(tx[i], ty[i] + m), add(ty[i], tx[i] + m);
add(tx[i] + m, ty[i]), add(ty[i] + m, tx[i]);
}
}
solve();
int flag = 0;
for(int i = 1; i <= m; ++ i){
if(Belong[i] == Belong[i + m]){
flag = 1; break;
}
}
if(flag) printf("NO\n");
else printf("YES\n");
return 0;
}