食物链--poj1182(并查集含有关系)
http://poj.org/problem?id=1182
题意应该就不用说了
再次回到食物链这道题,自己写了一遍,一直wa...原因竟然是不能用多实例,我也是醉了,但是我真的彻底的理解了,那些关系之间的转化,和上面那道差不多;
这道中的 r[i]表示i和f[i]之间的关系;
r[i] = 0,表示 i 和 f[i] 同类,
r[i] = 1, 表示 i 被 f[i] 吃;
r[i] = 2, 表示 i 吃 f[i];
至于为什么这样表示的看下面这些;
首先两个动物之间的关系只有三种即:同类,吃别人,被别人吃;
题中说了,如果出现 A吃B,B吃C,则 C吃A
下面所说的 吃 和 被吃 都是 i 对 f[i] 而言的, 吃 就是i吃f[i] ,被吃 就是i被f[i]吃;
同样我们可以得到 :
吃 + 吃 = 被吃; 式1;
被吃 + 吃 = 同类; 式2;
吃 + 同类 = 吃; 式3;
由上面可以看出同类用0表示,吃可以用1表示,被吃可以用2表示;
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #include <stack> #include <map> #include <vector> using namespace std; typedef long long LL; #define N 52100 #define met(a, b) memset(a, b, sizeof(a)) #define INF 0x3f3f3f3f int f[N], r[N]; int Find(int x) { int k = f[x]; if(x!=f[x]) { f[x] = Find(f[x]); r[x] = (r[x] + r[k]) % 3; } return f[x]; } int main() { int n, m, ans; scanf("%d %d", &n, &m); for(int i=0; i<=n; i++) f[i] = i, r[i] = 0; ans = 0; while(m --) { int op, x, y; scanf("%d %d %d", &op, &x, &y); if( x > n || y > n || (x == y && op == 2)) { ans++; continue; } op --;///表示 x 指向 y 的关系; int px = Find(x); int py = Find(y); if(px != py) { f[px] = py; r[px] = (r[y] - op - r[x] + 3) % 3; } else if(px == py && (r[x]+op)%3 != r[y]) ans++; } printf("%d\n", ans); return 0; }
推荐一个关系推倒的其他方法的博客http://www.cnblogs.com/wuyiqi/archive/2011/08/24/come__in.html