c++algorithmdata-structuresdisjoint-setsdisjoint-union

Disjoint set data structure : track size of each tree


Below is my implementation to keep track of the size of each tree in the disjoint set forest.

Can you please tell me what is wrong with it ? I am trying to solve UVa problem https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=3638

#include <iostream>
#include <cstdio>
#include <unordered_map>
using namespace std;

class Node {
    public :
    int id;
    Node *parent;
    unsigned long long rank;



    Node(int id) {
        this->id = id;
       // this->data = data;
        this->rank =1; //size here
        this->parent = this;
    }
    friend class DisjointSet;
};

  class DisjointSet {
    unordered_map<int,Node*> nodesMap;

    Node *find_set_helper(Node *aNode) {

        if (aNode == aNode->parent) {
            return aNode->parent;
        }
        return find_set_helper(aNode->parent);
    }

    void link(Node *xNode,Node *yNode) {
        if( xNode->rank > yNode->rank) {
            yNode->parent = xNode;
            xNode->rank += yNode->rank;
        }
        // else if(xNode-> rank < yNode->rank){
        //     xNode->parent = yNode;
        //     yNode->rank += xNode->rank;
        // }
        else {
            xNode->parent = yNode;
            yNode->rank += xNode->rank;
        }
    }
public:
    DisjointSet() {

    }

    void AddElements(int sz) {
        for(int i=0;i<sz;i++)
            this->make_set(i);
    }

    void make_set(int id) {
        Node *aNode = new Node(id);
        this->nodesMap.insert(make_pair(id,aNode));
    }

    void Union(int xId, int yId) {
        Node *xNode = find_set(xId);
        Node *yNode = find_set(yId);

        if(xNode && yNode)
          link(xNode,yNode);
    }

    Node* find_set(int id) {
      unordered_map<int,Node*> :: iterator itr = this->nodesMap.find(id);
      if(itr == this->nodesMap.end())
          return NULL;

      return this->find_set_helper(itr->second);
    }



    ~DisjointSet(){
        unordered_map<int,Node*>::iterator itr;
        for(itr = nodesMap.begin(); itr != nodesMap.end(); itr++) {
            delete (itr->second);
        }
    }

};
int main() {

    int n,m,k,first,cur;

    //freopen("in.in","r",stdin);

    scanf("%d %d",&n,&m);

    while(n != 0 || m != 0) {

        DisjointSet *ds = new DisjointSet();
        ds->AddElements(n); // 0 to n-1

        //printf("\n n = %d m = %d",n,m);


        for(int i=1;i<=m;i++) {
            scanf("%d",&k);
            //printf("\nk=%d",k);
            if ( k > 0 ) {

                scanf("%d",&first);
                for(int j=2;j<=k;j++) {
                    scanf("%d",&cur);
                    ds->Union(first,cur);
                }
            }
        }

        Node *zeroSet = ds->find_set(0);
       // unsigned long long count = ds->getCount(zeroSet->id);
        printf("%llu\n",zeroSet->rank);
        delete ds;

        scanf("%d %d",&n,&m);
    }

    return 0;
}

The link function in the above code does the job of updating the tree size.

The solution to the problem is to find the set which elements 0 belongs to and get the size of the representative element of the set. But I am getting wrong answer with this code.

Can you please help me


Solution

  • In your Union function, check if both nodes are already in the same set.

    if(xNode && yNode && xNode != yNode)
          link(xNode,yNode);