2 5 3 1 2 2 3 4 5 5 1 2 5
2 4
这道题是并查集问题,过几天写一个并查集的专题,这次就先把代码附上,以供参考
附上代码:
#include <iostream> #include <algorithm> #include <cstring> #include <string> #include <cstdio> #include <queue> #define MAX_N 5000 using namespace std; int ans; int par[MAX_N]; // 父亲 int Rank[MAX_N]; // 树的高度 void init(int n) // 初始化n个元素 { for(int i = 0;i < n;i++) { par[i] = i; // 初始化 将 n 个数的根都定位自己,形成 n 个数的森林 Rank[i] = 0; // 初始化 每棵树的深度为 0 } } int find(int x) // 查询根节点 { if(par[x] == x) // 寻找到根节点,返回根节点的值 return x; else return par[x] = find(par[x]); // 如果该节点不为根节点,就递归求其根节点 } void unite(int x,int y) // 合并 x 和 y 所属的集合 (哪个树高 则将 低树合并到高树上面,保持树的深度最优化,便于查找) { x = find(x); y = find(y); if(x == y) // 如果原本就属于同一个根,那说明在一个集合中,就不用合并了 return; if(Rank[x] < Rank[y]) // 如果 y 的树的高度比 x 的树的高度高的 par[x] = y; // 将 x 合并到 y 上面,以 y 为根 else par[y] = x; // 将 y 合并到 x 上面,以 x 为根 if(Rank[x] == Rank[y]) Rank[x]++; // 如果要合并的两颗树的长度相等,则树的高度 +1 } bool same(int x,int y) // 判断 x 和 y 是否属于同一个集合内! { return find(x) == find(y); // 属于统一集合返回值为 真,不属于返回值为 假 ! ( 既是 find(x) == find(y) 为真还是为假 ) } int main() { int n,m,t; cin >> t; while(t--) { scanf("%d%d",&n,&m); memset(par,0,sizeof(par)); // 对父节点进行清除 ans = n; // 初始化根的数目 init(n); for(int i = 0;i < m;i++) { int a,b; scanf("%d%d",&a,&b); if(same(a,b)) // 判断两个是否属于同一集合内 continue; else // 如果两个点原本不属于同一集合内,则将其合并 { unite(a,b); ans--; // 每两个树合并,树的数量少 1 } } cout << ans << endl; // 最后还有 ans 棵树,则需要 ans 张桌子就行了 } return 0; }