luoguP4171 [JSOI2010]饗宴

序文

こんにゃくはちょうど学び始めたので\(\テキスト{2-SAT} \) いくつかの場所で問題を解決するには、洗練されない場合がありので、私と一緒にクマを探して!

タイトル説明

表題は、単に標準的な手段(\ \テキスト{2-SAT } \) 問題モデル。だから我々は、最初にご紹介します\(\テキスト{2-SATを} \) 以下は個人的な少し一般化である)
(\テキスト{2-SAT} \)\:問題、それ抽象的で、これは
与えられました\(N- \)ブール変数(\ \ {x_nに関する\} \) および\(m個\)命題\((AA、B、BB)\) 場合命題が有効である\([X_A = AA] \ LOR [x_b =
BB] \) 今決定されるかどうかを解決\(\ {x_nに関するの\} \ ) の各要素に値を割り当てることで、全ての\(m個\)命題設定
:この問題のために、我々は、モデル図を構築する方法を見て
のために\(N \)異なる変数\(のx \) 我々は二つの点に分割し、それぞれ、\(のx \)が真であると\(X \)は偽である(ことができます\(私は\)を表す\(X_Iを\)真である、\(N-I + \)を表し\(X_I \)偽です)

そして、それぞれの側にするためにそこにある\((A、B)\) 我々はそれをこのような意味を与える:場合は\(\)が満たすべき、\の(b \)も満たさなければなりません

このように、我々は次のような方法は、溶液かどうかを判断する使用することができます。

  • ここで、可解性:\(\ FORALL \ I \でN- \) \(私は\)\(I + N \)と同じ強連結成分に属していません。
  • 何の解決策はどこ:\は(私はN- \に\ \ \存在しない)\(私は\)\(I + N \)は同じ強連結成分に属します。

それらが同時に真であるとされている表す命題強連結成分を持つ2つの点に属する、上記手法の施工面によれば、理由。
同じブール変数のためと\(X \)は同時に2つの値を持っていない、方法の正しさを決定するよりも、より多くのは明らかです。
その後、私たちはもう一度実行して、完成図\(\ {テキストTarjan} \ ) 上記のように判断してもよいです。
だから、次のステップは、最も重要である:マップを構築する方法?
実際には、これは困難な限り、抽象的ではない\(\ {x_nに関する\} \ ) と\(m個\) この質問に対して、例えば、約理解を深めるような命題。


基本的な考え方

我々は、(N- \)\ COMP成分抽象化(\ \ {x_nに関する\} \) 最初の\は、(私は\)漢の成分からなるサンプル表す\(X_Iを\) ポイント真である\(Iは\します)、)逆表す\(X_I \)が偽である(点\(N-I + \)
と同様に抽象化の上記方法によれば、各レビューの需要、
2つの命題は、各要件のために与えられている\ (P-、Q \) 私たちがいなくても二つの側面を行う\((\ LNOTのP、Q )\) と(\(\ LNOTのQ、P))\
(ここについては、\(のp \)\(q個\)何自分自身について考えることが可能です)


詳細注意事項

  • 以来、私たち\(N \)ポイントが2倍の領域を開くためになる食品の種類は、二つの点に分割されます。
  • 当社以来\(m個\)エントリの要件は二つの側面を持っていますので、スペースのエッジが二回開かれています。
  • 各時刻初期化、もし\(\ \ {用}テキスト ) サイクル空の配列は、(二上記参照)に列挙上限に注意を払わなければなりません。

参照コード

たぶん私は、あなたは、コードの私の理解を組み合わせることができ、非常に良いではない書き込みを、理解していませんああああああそれを賞賛するために、

/*--------------------------------
  Code name: meal.cpp
  Author: The Ace Bee
  This code is made by The Ace Bee
--------------------------------*/
#include <cstdio>
#include <cstring>
#define rg register
#define fileopen(x)                             \
    freopen(x".in", "r", stdin);                \
    freopen(x".out", "w", stdout);
#define fileclose                               \
    fclose(stdin);                              \
    fclose(stdout);
const int MAXN = 233;
const int MAXM = 2333;
inline int min(int a, int b) { return a < b ? a : b; }
inline int read() {
    int s = 0; bool f = false; char c = getchar();
    while (c < '0' || c > '9') f |= (c == '-'), c = getchar();
    while (c >= '0' && c <= '9') s = (s << 3) + (s << 1) + (c ^ 48), c = getchar();
    return f ? -s : s;
}
int tot, head[MAXN], nxt[MAXM], ver[MAXM];
inline void Add_edge(int u, int v)
{ nxt[++tot] = head[u], head[u] = tot, ver[tot] = v; }
int n, num, dfn[MAXN], low[MAXN];
int st[MAXN], top, co[MAXN], col;
inline void tarjan(int u) {
    dfn[u] = low[u] = ++num, st[++top] = u;
    for (rg int v, i = head[u]; i; i = nxt[i]) {
        if (!dfn[v = ver[i]])
            tarjan(v), low[u] = min(low[u], low[v]);
        else
            if (!co[v]) low[u] = min(low[u], dfn[v]);
    }
    if (dfn[u] == low[u]) {
        ++col;
        do co[st[top]] = col, --top;
        while (st[top + 1] != u);
    }
}
inline void init() {
    tot = col = num = top = 0;
    memset(co, 0, sizeof co);
    memset(dfn, 0, sizeof dfn);
    memset(low, 0, sizeof low);
    memset(head, 0, sizeof head);
}
int main() {
//  fileopen("meal");
    char sa[10], sb[10];
    for (rg int T = read(); T; --T) {
        init();
        int n = read();
        for (rg int m = read(); m; --m) {
            scanf("%s%s", sa, sb);
            int a = 0, lena = strlen(sa);
            for (rg int i = 1; i < lena; ++i)
                a = (a << 3) + (a << 1) + (sa[i] ^ 48);
            int b = 0, lenb = strlen(sb);
            for (rg int i = 1; i < lenb; ++i)
                b = (b << 3) + (b << 1) + (sb[i] ^ 48);
            if (sa[0] == 'h' && sb[0] == 'h')
                Add_edge(a + n, b), Add_edge(b + n, a);
            else if (sa[0] == 'h' && sb[0] == 'm')
                Add_edge(a + n, b + n), Add_edge(b, a);
            else if (sa[0] == 'm' && sb[0] == 'h')
                Add_edge(a, b), Add_edge(b + n, a + n);
            else if (sa[0] == 'm' && sb[0] == 'm')
                Add_edge(a, b + n), Add_edge(b, a + n);
        }
        for (rg int i = 1; i <= n << 1; ++i)
            if (!dfn[i]) tarjan(i);
        int flag = 1;
        for (rg int i = 1; i <= n; ++i)
            if (co[i] == co[i + n]) { flag = 0; break; }
        puts(flag ? "GOOD" : "BAD");
    }
//  fileclose;
    return 0;
}

エンドSahua \(qwq \)

おすすめ

転載: www.cnblogs.com/zsbzsb/p/11261844.html