前置知识
简单的查找(带路经压缩):
| int find(int x){ return x == fa[x] ? x : fa[x] = find(fa[x]); }
|
查找(这里可以数据小完全不需要用启发式合并):
| void merge(int x,int y){ int f = find(x),t = find(y); fa[f] = t; }
|
查阅资料可知,只用路径压缩,不用启发式合并的平均时间复杂度为 \(\mathcal{O}(\alpha (n))\)
,最坏时间复杂度为 \(\mathcal{O}(m \log
n)\) 。
思路
首先可以将每个元素看成点,化合物看成边,因为如果有超过 3
个物品互相形成化合物就会爆炸,所以会爆炸的条件可以看成两个是在同一祖先(在同一集合)中,(如果这两个点有一个祖先的话,合并就会有
3 个物品在一起的)。
每一次都将不在一个集合中两个数合并。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| #include<cstdio> #include<iostream>
using namespace std;
int fa[100010];
int find(int x){ return x == fa[x] ? x : fa[x] = find(fa[x]); }
int main() { int x,y; while(scanf("%d",&x) == 1){ \\ 注意输入 for(int i=1;i<=100010;i++) fa[i] = i; int ans = 0; while(x != -1){ scanf("%d",&y); int f = find(x),t = find(y); if(f == t) ans ++; else fa[f] = t; scanf("%d",&x); } cout<<ans<<endl; } return 0; }
|