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

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