「加重互いに素セット」パリティゲーム

パリティゲーム

元の質問へのリンク:パリティゲーム

効果の対象に

あなたの競合のロジックを尋ねるように頼むN間隔、あなたはそれを1とパリティを与える各区間を与えます

問題のトピックソリューション

重みのセットと、チェック私は右でチェックしてみましょうし、より深い理解を設定し、設定を確認する権利を持つとの質問は(この質問の途中で)二つに分けることができます

  • 「サイドバンドパワー」互いに素セット
  • 「拡張フィールド」互いに素セット

どちらの方法は、第一溶液を第二の溶液中で、最も一般的である、思考の違いによって引き起こされるのは、最初のために検討させて、達成するための最も簡単なコードです

サイドバンドの権利は、明らかに、我々はエッジ互いに素セットの店舗右側を操作したい、我々はここで、ルートノードのXORに現在のノードの値を表すためにそれが何を意味し、それを維持するために、どのようにDを使うのか?我々は2つに接続されているストレージのそれぞれの側で同じである同じパリティに属していることを意味し、右側は0であり、1が異なる場合、すべてのエッジの重みは、すべてのルートノードから独自のパスが排他的論理和をxはアップ、あなたはXノードと同じパリティのルートノードかどうかを確認することができますので、我々が得るまでのルートノードのXORのXOR値にルートノードに任意の2点、xとyのXORノードで判断することができます値は我々が0の値が何の競合を示していない場合、競合は、説明の場合は、その後私たちの現在の尋問とパリティは、Xorのだった、任意の2点間のXOR値に必要があるということです

それが私たちのクエリを解決するために行われている、我々は合併の問題を解決します、そして最後の段落が続く、我々は現在のx、yの2点とそのルーツP、Q、Qを持ったpへの接続を行います子ノード、そして私たちが求めているがd [P] A、D [P]どのように需要がありますか?私たちは、現在知られている情報D [X]とD [Y]、我々はX〜Pとy〜Qを求めているされているのp〜qは、我々はX〜PによるX〜Yを知って、yは〜Q 、P〜組成物Q、XYのその後パリティ(ここによって\(cnt_ {X、Y} \) パリティのうちのいずれか2つを表すために、パリティは、どのように入力を与えた?来る)\( cnt_ {X、Y} = D [X] Xord [Y] Xord [P] \) 、我々が得ることができる\(D [P] = D [X] Xord [Y] Xorans_ {X、Y} \) の、その後、操作が完了したマージ。

2の完了後、この質問は、範囲内で与えられているので、我々はむしろポイントよりも、問題そのものを分析する必要があるので、我々はポイントに間隔、間隔を指すように変換する必要がありますか?私は非常に精通感じ?はい、確かに我々は非常に精通している防衛この質問では同様の方法で接頭辞を使用し、パリティを保存することです使用され、それが何を意味するのでしょうか?詳細その質問の上に見ることができ、我々はポイントに変換したいので、私は、この質問のアップに変換、ここでそれらを繰り返すことはしません、これは確かにデータ範囲ではありません、我々は離散考えます。

離散化した後、我々はシーケンスを取得するので、この配列はしっかりと次のポイントであり、ここでは、我々は上記転写ポイント範囲を介して取得することができます、例えば、我々は今、範囲マージしたい\(L、Rを\ )、それは実際に\(L、Rの\)パリティは、すでに知られており、(ここで立ち往生多くの人々は、維持するためにばらばらのセットで多くの人が考えていなかったがあり、ここで動作する方法がわかりません。.. 、、、カード上のルーチン)\(L - 1 \)前述のパリティの特定の値にも一定知られているが、我々はします(R&LTを\ \)\(L - 1 \)とと我々は二つの部分のパリティを維持するように、チャールズは、(答えは明らかである理由?を考える)メンテナンスを設定し、2つのセクションでは、マージ。

上記の情報に基づいて、我々はこの問題は、次のコードを持っていました

//#define fre yes

#include <cstdio>
#include <algorithm>

const int N = 20005;
int ele[N << 1];
struct message {
    int l, r, ans;
} arr[N];

bool flag;
namespace Union {
    int par[N], d[N];
    inline void init(int n) {
        for (int i = 1; i <= n; i++) {
            par[i] = i;
        }
    }
    
    int find(int x) {
        if(par[x] == x) return par[x];
        int rt = find(par[x]);
        d[x] ^= d[par[x]];
        return par[x] = rt;
    }
    
    inline void unite(int x, int y, int a, int b, int i) {
        par[a] = b;
        d[a] = d[x] ^ d[y] ^ arr[i].ans;
    }
    
    inline void solve(int x, int y, int i) {
        if((d[x] ^ d[y]) != arr[i].ans) {
            printf("%d\n", i - 1);
            flag = 1;
        } 
    }
}

int m;
inline void discrete(int n) {
    std::sort(ele + 1, ele + 1 + n * 2);
    m = std::unique(ele + 1, ele + 1 + n * 2) - ele - 1;
}

int ask(int x) {
    return std::lower_bound(ele + 1, ele + 1 + m, x) - ele;
}

int main() {
    static int n, T;
    scanf("%d %d", &T, &n);
    for (int i = 1; i <= n; i++) {
        int x, y; char c[6];
        scanf("%d %d %s", &x, &y, c + 1);
        arr[i].l = x; arr[i].r = y;
        arr[i].ans = (c[1] == 'e' ? 0 : 1);
        ele[i] = x - 1; ele[i + n] = y;
    } 
    
    discrete(2 * n);
    Union::init(m);
    
    for (int i = 1; i <= n; i++) {
        int x = ask(arr[i].l - 1);
        int y = ask(arr[i].r);
        int p = Union::find(x), q = Union::find(y);
        if(p == q) {
            Union::solve(x, y, i);
            if(flag) return 0;
        } else Union::unite(x, y, p, q, i);
    } printf("%d\n", n);
    return 0;
}

そして、私たちは第二の方法、説明しましょう拡張フィールド互いに素セットを、第2の方法は、よりシンプルな考え方で、コードは、それを操作する方法、それは場所での操作そのような知識を伴わないので実装する方が簡単ですか?

各ノード\(X \)は 2つのノードに分割されている\(ODD X_ {} \)\(X_ {も} \)の和を表し、[x]は奇数との和である[X]であっても、私たちはしばしばありますこれら2つのノード追加xは、「奇数フィールド」となると「偶数フィールド。」

次に、以下の場合、離散的なセットが存在するであろう- \(1 \ L)\(R&LTの\)値は\(X \)\(Y \)に設けられ、\(CNT \)二つのパリティ(ここでは、読み取り専用)

  • もしマージCNT = 0 \(X_ {奇数} \)\(ODD Y_ {} \)、\ (さえX_ {} \)\(さえY_ {} \) これは、「xが奇数である」と、それらは同等の情報であり、相互に導入されてもよい「yが偶数である」「xが偶数である」とお互いに導入することができる「yが奇数である」ことを意味します。
  • もしマージCNT = 0 \(X_ {奇数} \)\(さえY_ {} \)、\ (さえX_ {} \)\(ODD Y_ {} \) これは、「xが奇数である」ことを意味し、「yが偶数であり、」お互いに導入することができ、「xが偶数である」とお互いに導入することができる「yが奇数である」、それらは同等の情報です。(なぜ自問してみてもいいですか?お互いを起動することができます)

また合わせ、このアプローチは非常にある処理後の(x、y、0)(Y、Zは、1)と2人の関係は、X、Zも明らかな関係であることは明らかであり、変速機の上記関係を維持します非存在下で地図上のノード間の接続性を維持するが、複数のフィールドに対応するように拡張すると、より多くの関係を転送します

X場合、yはに対応する\(X_ {奇数} \)\が(Y_ {奇数}が\)同じセットで、それは両方とも、同じパリティを有するX、Yは、に対応する場合、その意味する\(X_ {奇数} \)\ (Y_ {も} \)同じセットで、それが両方の、異なるパリティが知られています

したがって、上記の情報は、我々はコードを取得することができ、次のように、コードがあります

//#define fre yes

#include <cstdio>
#include <algorithm>

const int N = 20005;
int ele[N << 1];
struct message {
    int l, r, ans;
} arr[N];

bool flag;
namespace Union {
    int par[N], d[N];
    inline void init(int n) {
        for (int i = 1; i <= n; i++) {
            par[i] = i;
        }
    }
    
    int find(int x) {
        if(par[x] == x) return par[x];
        return par[x] = find(par[x]);
    }
    
    inline void unite(int x, int y) {
        int a = find(x);
        int b = find(y);
        if(a == b) return ;
        
        par[a] = b;
    }
}

int m;
inline void discrete(int n) {
    std::sort(ele + 1, ele + 1 + n * 2);
    m = std::unique(ele + 1, ele + 1 + n * 2) - ele - 1;
}

int ask(int x) {
    return std::lower_bound(ele + 1, ele + 1 + m, x) - ele;
}

int main() {
    static int n, T;
    scanf("%d %d", &T, &n);
    for (int i = 1; i <= n; i++) {
        int x, y; char c[6];
        scanf("%d %d %s", &x, &y, c + 1);
        arr[i].l = x; arr[i].r = y;
        arr[i].ans = (c[1] == 'e' ? 0 : 1);
        ele[i] = x - 1; ele[i + n] = y;
    } 
    
    discrete(2 * n);
    Union::init(m * 2);
    
    for (int i = 1; i <= n; i++) {
        int x = ask(arr[i].l - 1);
        int y = ask(arr[i].r);
        int x_odd = x, x_even = x + m;
        int y_odd = y, y_even = y + m;
        if(arr[i].ans == 0) {
            if(Union::find(x_odd) == Union::find(y_even)) {
                printf("%d\n", i - 1);
                return 0;
            }
            
            Union::unite(x_odd, y_odd);
            Union::unite(x_even, y_even);
        } else {
            if(Union::find(x_odd) == Union::find(y_odd)) {
                printf("%d\n", i - 1);
                return 0;
            }
            
            Union::unite(x_odd, y_even);
            Union::unite(x_even, y_odd);
        }
    } printf("%d\n", n);
    return 0;
}

おすすめ

転載: www.cnblogs.com/Nicoppa/p/11576748.html
おすすめ