POJ1733 Parity game
——————帶權離散化並查集
算法小白在網上看了很多的解題方式
但是很多都只有一個大致思路
但對於我還有一些初學者來說,特別難理解
所以我找了網上的一篇比較易懂的解題方法
但用自己的代碼重新實現
並且加上詳細註釋
代碼如下
//https://blog.csdn.net/u013480600/article/details/21128299 很好的解釋(離散化)
//https://blog.csdn.net/dominating413421391/article/details/47103281
//https://blog.csdn.net/dominating413421391/article/details/47100515 類似題POJ1962
//帶權並查集+離散化+合理的路徑壓縮
//用奇+奇的偶的思想來做,特別的相減也是一樣的
#include<iostream>
#include<cstdio>
#include<cstring>
#include<map>
#include<algorithm>
#include<stdlib.h>
using namespace std;
const int maxn = 2*5e3+10;//因爲串的長度特別長,不能存
int len,m;//長度和命令 //但是我們發現,數據只有5e3,即有效的節點只有2*5e3個
char cmd[10]; //所以我們只存代表區間的端點
int father[maxn],to_rel[maxn]; //存父節點,和i點與其父節點的奇偶
map<int,int> point;
void init();//初始化
int find(int);//找父節點
bool Uion(int,int,int);//合併兩個節點,返回值代表是否衝突
int main()
{
// freopen("./in.txt","r",stdin);
int index = 0,ans = 0,flag = 0;//離散化節點,ans代表錯誤的行
int odd_even; //奇偶位
init();//初始化
scanf("%d%d",&len,&m);
for(int i = 0;i < m;i++)
{
int a,b; scanf("%d%d%s",&a,&b,&cmd);
// printf("%d %d %s\n",a,b,cmd);
if(flag) continue;
a--;//我們將區間化爲(a,b]半開半閉區間,好讓區間首位相接 ps(1,2)->(0,2] (3,4)->(2,4]可以由1鏈接到2->4
if(point.find(a) == point.end()) point[a] = index++; //如果沒有找到,說明是一個新的點
if(point.find(b) == point.end()) point[b] = index++;
int x = point[a], y = point[b]; //獲取離散化之後的下標
if(cmd[0] == 'e') odd_even = 0;//偶數
else odd_even = 1;
if(!Uion(x,y,odd_even)) flag = 1;//此處與前面矛盾
else ans++;
}
printf("%d\n",ans);
// freopen("CON","r",stdin);
// system("pause");
return 0;
}
void init(){
for(int i = 0;i < maxn;i++){
father[i] = i;
to_rel[i] = 0;//開始全部不確定所以全部都初始化爲0
}
}
int find(int x) //尋找根節點並且路徑壓縮+奇偶數組更新,每次都是在Uion中更新
{
if(x == father[x]) return x;
else{
int rel = father[x];//x的原先根節點
father[x] = find(father[x]);//必須在此位置,不能放到最後,從裏到外一層層更新
to_rel[x] = (to_rel[x]+to_rel[rel])%2;//奇數+奇數=偶數 0是偶數
return father[x];
}
}
bool Uion(int x,int y,int d)
{
int fx = find(x);//找到與x同集合的根
int fy = find(y);//同上
if(fx == fy) //說明在一個集合中,可以判斷命令是否正確
{
if((to_rel[x]+to_rel[y])%2 == d) return true;
//x到y的奇偶性=x->root+y->root%2畫圖就可以理解了
else return false;
}
else{//說明無法判斷,更新數據
father[fx] = fy;//更新父節點 ps:fx的子節點對fx的距離在下次find的時候更新
to_rel[fx] = (to_rel[x]+to_rel[y]+d)%2;//畫圖以便理解,to_rel[x/y]都是x,y到自己根的距離
}
return true;
}