我在在线竞赛中遇到了这个问题,我试图使用Disjoint Set Data-structure解决它。
问题定义:
鲍勃在学校游览期间访问核电站。他观察到工厂中有n个核棒,核棒的初始效率为1.经过一段时间后,核棒开始相互融合并结合形成一个组。该过程将核棒的效率降低到组的大小的平方根。鲍勃是一名好奇的学生,想要在一段时间后知道核电站的总效率。这是通过添加组的效率来获得的。最初所有棒都属于它自己的1号组。有f融合。如果rod1和rod2融合,则意味着它们的基团融合了。
示例输入:
5 2
1 2
2 3
示例输出:
3.73
解释
n = 5融合= 2
组1,2,3 => 1.73(sqrt(3))
组4 => 1
组5 => 1
总=(1.73 + 1 + 1)= 3.73
我的代码:
#include <iostream>
#include <set>
#include <vector>
#include <stdio.h>
#include <math.h>
#include <iomanip>
using namespace std;
typedef long long int lli;
vector<lli> p,rank1,setSize; /* p keeps track of the parent
* rank1 keeps track of the rank
* setSize keeps track of the size of the set.
*/
lli findSet(lli i) { return (p[i] == i) ? i : (p[i] = findSet(p[i])); }
bool sameSet(lli x,lli y) { return findSet(x) == findSet(y); }
void union1(lli x,lli y) { // union merges two sets.
if(!sameSet(x,y)) {
lli i = findSet(x), j = findSet(y);
if(rank1[i] > rank1[j]) {
p[j] = i;
setSize[i] += setSize[j];
}
else {
p[i] = j;
setSize[j] += setSize[i];
if(rank1[i] == rank1[j])
rank1[j]++;
}
}
}
int main() {
freopen("input","r",stdin);
lli n;
cin >> n; //number of nuclear rods
setSize.assign(n,1); //Initialize the setSize with 1 because every element is in its own set
p.assign(n,0);
rank1.assign(n,0); //Initialize ranks with 0's.
for(lli i = 0; i < n; i++) p[i] = i; //Every set is distinct. Thus it is its own parent.
lli f;
cin >> f; //Number of fusions.
while(f--){
lli x,y;
cin >> x >> y; //combine two rods
union1(x,y);
}
double ans;
set<lli> s (p.begin(),p.end()); //Get the representative of all the sets.
for(lli i : s){
ans += sqrt(setSize[i]); //sum the sqrt of all the members of that set.
}
printf("\n%.2f", ans); //display the answer in 2 decimal places.
}
以上代码似乎适用于所有测试用例但只有一个。
我的代码失败的输入为here。
预期产量为:67484.82
我的输出:67912.32
由于输入非常大,我无法解决出错的地方。
真的很感激任何帮助。提前致谢。
答案 0 :(得分:1)
p
包含元素的直接父级,而不是findSet
个值。因此,当您执行set<lli> s (p.begin(),p.end());
时,您可以在那里拥有其他元素。
我可以通过两种方式来解决这个问题:
setSize[i] += setSize[j]
后,设置setSize[j] = 0
。这样,中间父母就不会为这笔款项做出贡献。