我正在编写代码以在图表上执行Union-Find,
第一行输入是:
n m [n是节点数,m是边数]
然后是m行,表示哪两个节点连接了
当我遇到每个边缘时,我执行联合操作,以连接节点。执行并集后,我还想知道最大子集和最小子集的大小
到目前为止,这是我的代码,
#include <iostream>
using namespace std;
int arr[100001];
int size[100001];
void initialize(int n){
for(int i=1; i<=n; i++){
arr[i] = i;
size[i] = 1;
}
}
int root(int a){
while(arr[a] != a){
//Path compression
arr[a] = arr[arr[a]];
a = arr[a];
}
return a;
}
void weighted_union(int a, int b){
int root_a = root(a);
int root_b = root(b);
//Perform union, if the two elements are not already in the same subset
if(root(a) != root(b)){
if(size[root_a] < size[root_b]){
arr[root_a] = root_b;
size[root_b] += size[root_a];
}
else{
arr[root_b] = root_a;
size[root_a] += size[root_b];
}
}
}
void print_result(int n){
int max_size = 1;
int min_size = 100000;
for(int i=1; i<=n; i++){
//If it's a root node, then check the size
if(arr[i] == i){
if(size[i] > max_size){
max_size = size[i];
}
if(size[i] < min_size){
min_size = size[i];
}
}
}
cout<<max_size - min_size<<endl;
}
int main() {
//For fast IO
ios_base::sync_with_stdio(false);
cin.tie(NULL);
int n,m,a,b;
cin>>n>>m;
initialize(n);
for(int edge=0; edge<m; edge++){
cin>>a>>b;
weighted_union(a,b);
print_result(n);
}
return 0;
}
我正在使用暴力来获取最小尺寸的子集和最大尺寸的子集。此代码在Sphere Online Judge中超时。
获得最小尺寸子集和最大尺寸子集的更有效方法是什么。
答案 0 :(得分:0)
使用不相交集的方法是正确的。但是你得到了一个TLE,因为你的复杂性是O(N*Q)
,它不会在看到约束时传递。您可以优化算法以获得O(Q*log(N))
。
你基本上需要在任何时间点的最大和最小尺寸。这些只会在更新期间更改。您可以通过在每次更新后检查新形成的组的大小&gt;来跟踪O(1)
中的最大大小。最大。对于min,您可以使用BST存储按大小排序的节点的值。更好地使用C ++ STL set
。对于您执行的每个联合,从树中删除两个节点(我的意思是与查询节点对应的父节点)并插入具有大小的新父节点。由于插入和删除需要O(logN)
时间,因此您的复杂性将变为O(QlogN+NlogN)
[O(NlogN)
以构建树]