POJ 1182 食物链
我感觉我学过的并查集一下子看不懂了。总之不是简单的并查集,而是种...种类并查集?简单来说就是基本的并查集只需要判断两个是否属于同一组,而种类并查集则需要判断两个个体之间的关系(同一组?你吃我?我吃你?)
推荐一个题目详解博客:Click HERE
解题思路:
总之我写题解也是为了给自己以后好复习,这里让我茅塞顿开的一些提示:
- 两个个体x和y,如果 par[x] = par[y],则他们是属于一个组的。(基本并查集概念),相同的,par[x+N] = par[y+N],par[x+2*N] = par[y+2*N]。
- 两个个体x和y,如果 par[x] = par[y+N],表示 x 吃 y 。相同地,par[x+N] = par[y+2*N],par[x+2*N] = par[y]也表示前者吃后者.
- 两个个体x和y,如果 par[x] = par[y+2*N],表示 x 被 y 吃。
- 题目隐藏条件:x吃y y吃z z吃x 形成一个条食物链。
x吃y,y吃z。为什么可以传递出z吃x?
x吃y ;par[x] = par[y+N] & par[x+N] = par[y+2*N] & par[x+2*N] = par[y]
y吃z ;par[y] = par[z+N] & par[y+N] = par[z+2*N] & par[y+2*N] = par[z]
故:par[x] = par[y+N] = par[z+2*N];即z吃x;
代码参考自:Click HERE
#include <iostream>
#include <cstdio>
#define MAX_N 500000
using namespace std;
int N, K, ans = 0;
int par[MAX_N];
void init(){
for(int i = 0; i < N*3; i++)
par[i] = i;
}
int find(int x){
if(par[x] == x)
return x;
else
return par[x] = find(par[x]); //路径压缩
}
void unite(int x, int y){
int px = find(x);
int py = find(y);
if(px != py)
par[px] = py;
}
int main(){
scanf("%d%d", &N, &K);
init();
for(int i = 0; i < K; i++)
{
int type, x, y;
scanf("%d%d%d", &type, &x, &y);
x -= 1, y -= 1;
if(x < 0 || x >= N || y >= N || y < 0)
{
ans++;
continue;
}
if(type == 1)//同类
{
if(find(x) == find(y+N) || find(x) == find(y+2*N))
{
ans++;
continue;
}
else
{
unite(x, y);
unite(x+N, y+N);
unite(x+2*N, y+2*N);
}
}
if(type == 2)//捕食
{
if(x == y || find(x) == find(y) || find(x) == find(y+2*N))
{
ans++;
continue;
}
else
{
unite(x, y+N);
unite(x+N, y+2*N);
unite(x+2*N, y);
}
}
}
printf("%d\n", ans);
return 0;
}
POJ 2492 臭虫也疯狂
我感觉每次两题 第二题都比第一题要简单 whatever 正好拿来增加勇气练手 其实第一题写过之后这题就很简单了 上题有三种关系 这里只有两种关系 所以2*N is appreciated.
校OJ能过 真滴自闭了 不知道为啥在POJ总WA 算辽
POJ 1703 各...各种姿势?
I promise this is the last one.
有一种不是用2*N这样的方法写的,用的rank来判断两个群之间的关系。