第一行:咕咕咕。
第二行:我原以爲並查集很簡單的。原以爲。因此我現在一看到說並查集“簡單有趣”的博客就心情複雜(不排除對人家來說真的簡單有趣)。(本博客下次更新會附送簡單並查集緩解心情)
第三行:誰能想到一道並查集我花了兩個晚上呢。
第四行:這道題需要多多複習,我現在也不是特別明白。
第五行:還是小白書友好一些。
第六行:真正的勇士,敢於wa題二十次。
並查集:快速判斷兩個或多個元素的關係,快速合併兩個集合
基礎的合併or查找父節點我就不寫了(包括遞歸查找和while循環查找)
本題POJ1182:兩種思路:一種類似於向量;另一種分作三個區間0 ~ n表示同類,n+1 ~ 2n表示被吃,2n+1 ~ 3n表示吃別的(白書給出的思想
所附代碼爲第一種思路(用相對關係來表示其關係)
會再抽個合適的時間去寫一下白書的代碼的(其實是學一下白書的代碼,因爲這個思路在關係合併那裏還是不太明白
留個坑
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#define maxn 500005
using namespace std;
//當前寫法爲按向量來寫
int f[maxn];
int r[maxn];//一個表示父節點一個表示關係(同類
void init()
{
for(int i = 0; i < maxn; ++i)
{
f[i]=i;
r[i]=0;
}
}
int tofind(int x)
{
if(x==f[x])
return x;
int a=f[x];
int b=x;
x=tofind(f[x]);
f[b]=x;
r[b]=(r[a]+r[b])%3;
return x;
}
void tojoin(int x,int y,int op)
{
int a=tofind(y);
f[a]=tofind(x);
r[a]=(3-r[y]+op-1+r[x])%3;
}
int main()
{
init();
int n,k;
int ans=0;
scanf("%d%d",&n,&k);
for(int i = 0; i < k; ++i)
{
int x,y,op;
scanf("%d%d%d",&op,&x,&y);
if(x>n||y>n||(op==2&&x==y))
ans++;
else
{
int r1=tofind(x);
int r2=tofind(y);//未合併過即沒有關係
if(r1==r2)
{
if(op==1)
{
if(r[x]!=r[y])
ans++;
}
else
{
if((3-r[x]+r[y])%3!=1)
ans++;
}
}
else
{
tojoin(x,y,op);
}
}
}
printf("%d\n",ans);
return 0;
}
附幾個很不錯的題解(有空再看看:
添加鏈接描述
添加鏈接描述
添加鏈接描述
再附幾個簡單的並查集緩緩心情SDNU1351