POJ - 1733 Parity game 並查集 擴展域解法 &帶邊權解法

題目大意

有一個01序列
每次給一個 兩個數x y 和他們之間的1的個數是奇數還是偶數
問 在第幾個給定的條件可以判斷這些條件存在矛盾

樣例

Sample Input
10
5
1 2 even
3 4 odd
5 6 even
1 6 even
7 10 odd
Sample Output
3

解法一: 帶邊權

思路
    利用前綴和思想。 a代表a的前綴和, 由於是01序列, 所以a就代表a的前面有多少個1, a 和 b 之間的1個數是偶數, 代表a - 1b 的奇偶性相同
在這裏插入圖片描述
代碼

#include <iostream>
#include <cstring>
#include <map>
#include <algorithm>

using namespace std;

const int N = 20010;

int f[N], d[N];
int n, m, cnt;
map<int, int> num;


int get(int a)
{
    if(num.count(a))  return num[a];
    return num[a] = ++cnt;
    
}

void init()
{
    for(int i = 0; i <= 20000; i++)
        f[i] = i;
}


int find(int x)
{
    if(f[x] == x) return x;
    int father = find(f[x]);  //如果他的父節點到根之間是偶數0, 他到父節點是奇數1, ^結果就是1,奇數。。。等等
    d[x] ^= d[f[x]];
    return f[x] = father;
}

int main()
{
    int n, m;
    scanf("%d%d", &n, &m);
    init();
    int ans = m;
    bool ff =- false;
    for(int i = 1; i <= m; i++)
    {
        
        string s;
        int a, b;
        cin >> a >> b >> s;
        a--;
        if(ff) continue;
        a = get(a); //離散化
        b = get(b);
        int t = 0;
        if(s == "odd")
            t = 1;
        int fa = find(a);
        int fb = find(b);
        if(fa == fb)
        {
            if((d[a] ^ d[b]) != t)
            {
                ans = i - 1;
                ff = true;
            }
        }
        else{
            f[fa] = fb;
            d[fa] = d[a] ^ d[b] ^ t;
        }
    }
    cout << ans << endl;
    
    return 0;
}

解法二:擴展域

思路

    a 和 a+n 代表奇偶性不同兩個條件, 這裏的a, b代表的是條件, 不是上一個解法中的數
    所以給定a, b, 如果他們之間是偶數, 那麼a, b爲同類,a + n, b + n也是同類
     如果是奇數a, b 就是異類, a + n, b就是同類

代碼

#include <iostream>
#include <cstring>
#include <map>
#include <algorithm>

using namespace std;

const int N = 40010, base = N / 2;

int f[N], d[N];
int n, m, cnt;
map<int, int> num;


int get(int a)
{
    if(num.count(a))  return num[a];
    return num[a] = ++cnt;
    
}

void init()
{
    for(int i = 0; i <= 40000; i++)
        f[i] = i;
}


int find(int x)
{
    if(f[x] == x) return x;
    return f[x] = find(f[x]);
}

int main()
{
    int n, m;
    scanf("%d%d", &n, &m);
    init();
    int ans = m;
    bool ff =- false;
    for(int i = 1; i <= m; i++)
    {
        
        string s;
        int a, b;
        cin >> a >> b >> s;
        a--;
        if(ff) continue;
        a = get(a); //離散化
        b = get(b);
        if(s == "even")
        {
            if(find(a) == find(b + base))
            {
                ans = i - 1;
                ff = true;
            }
            f[find(a)] = find(b);
            f[find(a + base)] = find(b + base);
        }
        else{
          if(find(a) == find(b))
          {
               ans = i - 1;
               ff = true;
          }
            f[find(a)] = find(b + base);
            f[find(a + base)] = find(b);
        }
    }
    cout << ans << endl;
    
    return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章