C ++中的Disjoint Set实现

时间:2017-01-21 09:53:16

标签: c++ algorithm disjoint-sets

我在在线竞赛中遇到了这个问题,我试图使用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

由于输入非常大,我无法解决出错的地方。

真的很感激任何帮助。提前致谢。

1 个答案:

答案 0 :(得分:1)

p包含元素的直接父级,而不是findSet个值。因此,当您执行set<lli> s (p.begin(),p.end());时,您可以在那里拥有其他元素。

我可以通过两种方式来解决这个问题:

  1. 使用循环将findSet(i)插入到集合中,而不是直接放入p
  2. 执行setSize[i] += setSize[j]后,设置setSize[j] = 0。这样,中间父母就不会为这笔款项做出贡献。