POJ1182 食物链(并查集)

来源:互联网 发布:腾讯云域名与ip绑定 编辑:程序博客网 时间:2024/05/01 19:52

题意:

中文题不解释

要点:

很经典的并查集问题,也很难。网上一共两种做法:一种是算相对类别偏移量,用了一系列找规律,难的爆炸,反正我看懂了但是再做一次肯定是做不出来的;另一种是将数组开三倍,表示所有的情况,这种我还可以尝试一下。


开三倍数组存储所有情况:

要点是将P[X]开成最大值的三倍,1~n表示当前x属于A;n+1~2n表示当前x属于B,2n+1~3n表示当前x属于C,每次合并时将x属于ABC的三种情况全部合并起来,这样就可以完全考虑。最后求假话数量,只要考虑对应的x属于的集合即可。这种方法内存虽然要求高了点,但实际运行时间还是少的。而且稍微好理解一点,还是用这种方法吧。

15316600Seasonal1182Accepted1276K250MSC++1094B2016-03-26 15:50:34

#include<stdio.h>#include<string.h>#include<stdlib.h>#define maxn 50050int p[3*maxn],rank[3*maxn];//将x对应A,x对应B,x对应C都储存下来int m, k;void init(){for (int i = 1; i <= 3 * m; ++i){p[i] = i;rank[i] = 0;}}int find(int x){if (p[x] == x) return x;return p[x] = find(p[x]);}void merge(int x, int y){x = find(x);y = find(y);if (x == y) return;if (rank[x] > rank[y])p[y] = x;else{p[x] = y;if (rank[x] == rank[y]) rank[y]++;}}bool same(int x, int y){return find(x) == find(y);}int main(){int d, x, y,num=0;scanf("%d%d", &m, &k);init();while (k--){scanf("%d%d%d", &d, &x, &y);if (x > m || y > m || (d == 2 && x == y)){++num;continue;}if (d == 1){if (same(x, y + m) || same(x, y + 2 * m)) ++num;//当x为A时y为B或C不满足条件else//不用考虑x为B或C的问题,因为下面已经将x=ABC三种情况全合并起来了{//如果出现x=A时y=B或C就说明x=B或C时也不满足条件merge(x, y);//为A时x与y相等merge(x + m, y + m);merge(x + 2 * m, y + 2 * m);}}if (d == 2){if (same(x, y) || same(x, y + 2 * m)) ++num;//当x, y同类,或者属于A的x吃了C的y,则为假话else{merge(x, y + m);//属于A的x吃了属于B的ymerge(x + m, y + 2 * m);//属于B的x吃了属于C的ymerge(x + 2 * m, y);//属于C的x吃了属于A的y}}}printf("%d\n", num);return 0;}


相对类别偏移量:

参考博客:点击打开链接

15316265Seasonal1182Accepted508K282MSC++833B2016-03-26 14:56:41

#include<stdio.h>#include<string.h>#include<stdlib.h>#define maxn 50050int n, k;int p[maxn], rank[maxn];//rank[x]用来表示x与p[x]的食物链关系void init(){for (int i = 1; i <= n; ++i){p[i] = i;rank[i] = 0;}}int find(int x){if (p[x] != x){int t = p[x];p[x] = find(p[x]);rank[x] = (rank[x] + rank[t]) % 3;//找规律得到}return p[x];}void merge(int x, int y,int d){int xf = find(x);int yf = find(y);p[xf] = yf;rank[xf] = (rank[y] - rank[x] + 2 + d) % 3;}int main(){int d, x, y,num=0;int xf, yf;scanf("%d%d", &n, &k);init();while (k--){scanf("%d%d%d", &d, &x, &y);if (x > n || y > n || (d == 2 && x == y))num++;else{xf = find(x);yf = find(y);if (xf == yf)//等于才能判断,不等于判断不了可以直接合并{if ((rank[x] - rank[y] + 3) % 3 != d - 1)num++;}elsemerge(x, y, d);}}printf("%d\n", num);return 0;}

0 0
原创粉丝点击