【JSOI2010】【BZOJ1823】满汉全席

【题目链接】

【前置技能】

  • Tarjan
  • 2-SAT【仅需知道图的收缩即可】

【题解】

  • 题意最简化之后就是:每个集合都含有2个元素,且这2个元素不允许同时取出,现给出一些取元素的规则,判断是否可行。
  • 显然就是一个裸的2-SAT,而且只要判断是否可行,不要求方案。Tarjan缩点后判断同一集合中的两个元素是否在同一个强连通分量中即可。
  • 时间复杂度 O ( N )

【代码】

#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;
}

猜你喜欢

转载自blog.csdn.net/six_solitude/article/details/80569650
今日推荐