满汉全席
题目链接:ybt金牌导航3-6-6 / luogu P4171
题目大意
就是你要做一些菜,对于每个菜你可以选两个方法的中的其中一个。
然后又一些评委,对于某个评委,他要求你某两道菜只要有一道要用它规定的方法来做。(两道菜规定的方法可能不一样)
然后问你能不能有一种方案使得所有评委的要求都满足。
思路
这道题其实就是裸裸的 2-SAT,你从二选一,两道菜之间的条件,全部满足这些字眼就看出是 2-SAT。
然后你会发现它就是模板题。
——>不会写模板题的点我看<——
注释也懒得写了,反正是跟模板题一样的,看模板题吧。
这里只要小改一下就过了。
代码
#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
struct node {
int to, nxt;
}e[500010];
int n, m, x, y, le[5001], KK, T;
char cx, cy;
int dfn[5001], low[5001], tmp;
int sta[5001], in[5001], n_n;
bool cant;
void csh() {
memset(e, 0, sizeof(e));
memset(le, 0, sizeof(le));
KK = 0;
memset(dfn, 0, sizeof(dfn));
memset(low, 0, sizeof(low));
tmp = 0;
memset(sta, 0, sizeof(sta));
memset(in, 0, sizeof(in));
n_n = 0;
cant = 0;
}
void add(int x, int y) {
e[++KK] = (node){y, le[x]}; le[x] = KK;
}
int another(int x) {
if (x > n) return x - n;
return x + n;
}
void tarjan(int now) {
dfn[now] = low[now] = ++tmp;
sta[++sta[0]] = now;
for (int i = le[now]; i; i = e[i].nxt)
if (!dfn[e[i].to]) {
tarjan(e[i].to);
low[now] = min(low[now], low[e[i].to]);
}
else if (!in[e[i].to]) low[now] = min(low[now], low[e[i].to]);
if (dfn[now] == low[now]) {
in[now] = ++n_n;
while (sta[sta[0]] != now) {
in[sta[sta[0]]] = n_n;
sta[0]--;
}
sta[0]--;
}
return ;
}
int main() {
scanf("%d", &T);
while (T--) {
scanf("%d %d", &n, &m);
csh();
for (int i = 1; i <= m; i++) {
cx = getchar();
while (cx != 'm' && cx != 'h') cx = getchar();
scanf("%d", &x);
cy = getchar();
while (cy != 'm' && cy != 'h') cy = getchar();
scanf("%d", &y);
if (cx == 'h') x += n;
if (cy == 'h') y += n;
add(x, another(y));
add(y, another(x));
}
for (int i = 1; i <= 2 * n; i++)
if (!dfn[i]) tarjan(i);
for (int i = 1; i <= n; i++)
if (in[i] == in[n + i]) {
cant = 1;
printf("BAD\n");
break;
}
if (!cant) printf("GOOD\n");
}
return 0;
}