POJ 1182 食物链

来源:互联网 发布:消防优化经济发展环境 编辑:程序博客网 时间:2024/05/16 10:28

1.题目描述:点击打开链接

2.解题思路:本题利用并查集解决。根据题意知,需要三个并查集,这里为了方便,给数组par均分为三段,分别记为A,B,C。通过下标来控制不同的集合。

那么接下来该如何处理每一条信息呢?当输入第一种信息时,表示u和v属于同一类,此时有三种可能,因此要把u和v分别合并到A,B,C中。如果是第二种,表示u吃v,那么也有三种情况:u在A中v在B中,u在B中v在C中,u在C中v在A中。

那么还有一个问题,如何判断信息是否合法呢?由于我们是把一个数组切割成了三大段,那么A,B,C其实是在同一组中的,而同一组中的所所有元素代表的情况要么同时发生,要么都不发生。比如如果u属于A和v属于B在同一个组里,那么如果u属于A为真,那么必有v属于B为真,反之同理。所以,只用判断u,v是否在同一个组中即可知该句话为真还是为假。

本题需要对并查集的性质深刻理解才能正确解题。

3.代码:

#define _CRT_SECURE_NO_WARNINGS #include<iostream>#include<algorithm>#include<string>#include<sstream>#include<set>#include<vector>#include<stack>#include<map>#include<queue>#include<deque>#include<cstdlib>#include<cstdio>#include<cstring>#include<cmath>#include<ctime>#include<functional>using namespace std;#define N 150000+10int par[N], rnk[N];int n, m;void init(int n){for (int i = 0; i < n; i++){par[i] = i;rnk[i] = 0;}}int find(int x){if (par[x] == x)return x;else return par[x] = find(par[x]);}bool same(int x, int y){return find(x) == find(y);}void unit(int x, int y){x = find(x); y = find(y);if (x == y)return;if (rnk[x] < rnk[y])par[x] = y;else{par[y] = x;if (rnk[x] == rnk[y])rnk[x]++;}}int main(){//freopen("t.txt", "r", stdin);scanf("%d%d", &n, &m);init(3 * n);int cnt = 0;for (int i = 1; i <= m; i++){int id, u, v;scanf("%d%d%d", &id, &u, &v);u--, v--;if (u >= n || v >= n || v < 0 || u < 0)cnt++;//编号非法else if (id == 1){if (same(u, v + n) || same(u, v + 2 * n))cnt++;//u和v实际上不属于同一个种类else{unit(u, v); unit(u + n, v + n); unit(u + 2 * n, v + 2 * n);//3种可能的情况}}else{if (same(u, v) || same(u, v + 2 * n))cnt++;//u和v是同一类 或者 实际上是v吃u(三种情况中只用挑一种即可)else{unit(u, v + n); unit(u + n, v + 2 * n); unit(u + 2 * n, v);}}}printf("%d\n", cnt);return 0;}

0 0