标签:利用 amp 情况 str union 变量 namespace 操作 nod
数组版:
int parent[MAX_N]; int rank[MAX_N]; void Init(int n){ for(int i = 0; i < n; ++i){ parent[i] = i; rank[i] = 0; } } int Find(int x){ if(parent[x] = x){ return x; } else { return Find(parent[x]); } } void Union(int x, int y){ x = Find(x); y = Find(y); if(x == y) return; if(rank[x] < rank[y]){ parent[x] = y; } else { parent[y] = x; if(rank[x] == rank[y]) rank[x]++; } }
结构体版:
struct Node { int rank; int parent; } node[MAX_N]; void Init(int n){ for(int i = 0; i < n; ++i){ node[i].parent = i; node[i].rank = 0; } } int Find(int x){ if(node[x].parent = x){ return x; } else { return Find(node[x].parent); } } void Union(int x, int y){ x = Find(x); y = Find(y); if(x == y) return; if(node[x].rank < node[y].rank){ node[x].parent = y; } else { node[y].parent = x; if(node[x].rank == node[y].rank) node[x].rank++; } }
解题思路:
这个题是非常经典的并查集问题。并查集作用:查询a和b是否属于同一组;合并a和b所在的组。注意并查集无法进行分割操作。利用题目中动物之间的相对关系可以建立一个并查集。对每一个元素,把它对父节点的关系用数组rank[i]表示,即relation,作为权值。0:与父节点同类 1:吃父节点 2:被父节点吃。
路径压缩。为了使查找效率提高,我们需要使树的高度尽可能小,让它只有一层,即在查找的过程中,把树中一条路径上的所有点都连在根节点上,从而加快了查找速度,与此同时,还要更新与此节点有关的其他变量,比如此节点与父节点的权值(父节点变为根节点),该树的高度等等。对于此题来讲,就是要更新节点与父节点的关系,因为此节点的父节点已经变为根节点。那么这里如何推导出此节点与根节点的关系呢。假设此节点为x,其父节点为y,y的父节点为z。则:
rank[x] rank[y] x与z的关系权值 0 0 0=(i + j)%3 0 1 1=(i + j)%3 0 2 2=(i + j)%3 1 0 1=(i + j)%3 1 1 2=(i + j)%3 1 2 0=(i + j)%3 2 0 2=(i + j)%3 2 1 0=(i + j)%3 2 2 1=(i + j)%3
推导公式:rank[x] = (rank[x] + rank[y]) % 3; 即对于i节点,更新公式为:rank[i] = (rank[i] + rank[parent[i]]) % 3。不过还有更简便的方法:模拟向量的运算x->z = x->y + y->z,所以rank[x] = (rank[x] + rank[y])% 3。对3取模是为了保证结果为0,1,2。
最后是集合的合并操作。合并操作并不复杂,复杂的是更新集合间的关系(即集合根节点的关系)。这里有大神使用向量的形式来计算更新关系权值,假设需要合并x和y,查询得知x和y的根节点分别为:x_p,y_p,如果将x_p连接到y_p,那么rank[x_p]即为x_p与根节点y_p的关系。x_p->y_p = x_p->x + x->y + y->y_p = (-x->x_p + x->y + y->y_p)。所以更新公式为rank[x_p] = (-rank[x] + type - 1 + rank[y] + 3) % 3。(加上3是为了防止出现负数的情况;对3取模是为了保证结果的取值范围)。type即为输入的num。type为1,x与y同类,type为2,x吃y。
Solution:from 专注如一
#include <cstdio.h> #include <cstring> #include <algorithm> using namespace std; const int MAX_N = 50000 + 10; int parent[MAX_N], rank[MAX_N]; void Init(int n){ for(int i = 0; i < n; ++i){ parent[i] = i; rank[i] = 0; } } int Find(int x){ if(parent[x] == x){ return x; } int y = Find(parent[x]); rank[x] = (ran[x] + ran[parent[x]]) % 3; return parent[x] = y; } int Union(int x, int y, int type){ x_p = Find(x); y_p = Find(y); if(x_p == y_p){ if((rank[x] - rank[y] + 3) % 3 == type - 1) return 0; return 1; } parent[x_p] = y_p; rank[x_p] = (-rank[x] + type - 1 + rank[y] + 3) % 3; return 0; } int main(){ int n, k, res = 0; int type, x, y; scanf("%d %d", &n, &k); Init(n); for(int i = 0; i < k; ++i){ scanf("%d %d %d", &type, &x, &y); if(x == y && type == 2) ++res; else if(x > n || y > n) ++res; else res += Union(type, x, y); } printf("%d\n", res); return 0; }
标签:利用 amp 情况 str union 变量 namespace 操作 nod
原文地址:http://www.cnblogs.com/Atanisi/p/7638809.html