【题目链接】
【前置技能】
- Tarjan
- 2-SAT【仅需知道图的收缩即可】
【题解】
- 题意最简化之后就是:每个集合都含有2个元素,且这2个元素不允许同时取出,现给出一些取元素的规则,判断是否可行。
- 显然就是一个裸的2-SAT,而且只要判断是否可行,不要求方案。Tarjan缩点后判断同一集合中的两个元素是否在同一个强连通分量中即可。
- 时间复杂度
【代码】
#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
#define LL long long
#define MAXN 410
using namespace std;
int Q, n, m;
int col[MAXN], sta[MAXN], top, dfn[MAXN], low[MAXN], tim, belong[MAXN], cnt;
vector <int> a[MAXN];
template <typename T> void chkmin(T &x, T y){x = min(x, y);}
template <typename T> void chkmax(T &x, T y){x = max(x, y);}
template <typename T> void read(T &x){
x = 0; int f = 1; char ch = getchar();
while (!isdigit(ch)) {if (ch == '-') f = -1; ch = getchar();}
while (isdigit(ch)) {x = x * 10 + ch - '0'; ch = getchar();}
x *= f;
}
void tarjan(int pos){
col[pos] = 1, sta[++top] = pos, low[pos] = dfn[pos] = ++tim;
for (unsigned i = 0, si = a[pos].size(); i < si; ++i){
int son = a[pos][i];
if (col[son] == 0) {tarjan(son); chkmin(low[pos], low[son]);}
if (col[son] == 1) {chkmin(low[pos], dfn[son]);}
}
if (low[pos] == dfn[pos]){
++cnt;
while (sta[top] != pos){
belong[sta[top]] = cnt;
col[sta[top]] = 2;
--top;
}
belong[sta[top]] = cnt;
col[sta[top]] = 2;
--top;
}
}
int id(int x, int opt){
return (x - 1) * 2 + opt + 1;
}
void add(int x, int y){
a[x].push_back(y);
}
int main(){
read(Q);
while (Q--){
read(n), read(m);
for (int i = 1; i <= 2 * n; ++i)
a[i].clear(), col[i] = dfn[i] = low[i] = belong[i] = 0;
for (int i = 1; i <= m; ++i){
char s, t; int u, v, x, y;
scanf("\n");
scanf("%c%d %c%d", &s, &u, &t, &v);
x = (s == 'h'), y = (t == 'h');
add(id(u, x ^ 1), id(v, y));
add(id(v, y ^ 1), id(u, x));
}
for (int i = 1; i <= 2 * n; ++i)
if (!col[i]) tarjan(i);
int fla = 1;
for (int i = 1; i <= n; ++i)
if (belong[id(i, 0)] == belong[id(i, 1)]) {fla = 0; break;}
if (fla) printf("GOOD\n"); else printf("BAD\n");
}
return 0;
}