Question

I have to use the union find algorithm to solve the traveling salesman problem. I prettymuch got it done except for one problem I've just discovered. As it processes each edge, it will check for a cycle, which is done with the whole parent array thing. The problem is that, when it gets to the last edge I need to add to complete the problem, since it is technically a cycle, it does not add the edge, so the path can not be completed. How can I differentiate a useless cycle from the cycle indiicating that we are done?

Here's the code I got so far

private int[] parent; //parent of each vertex
private int[] connection; //number of edges coming from a given vertex
private int[] subsize; //size of each subtree
boolean donepath;

public void GreedyAlgo(){
    ArrayList<Edge> newedges = new ArrayList<Edge>();
    for(int i = 0; i<graph.realedge.size();i++){
        if(donepath) break;
        Edge e= graph.realedge.get(i);
        int x = e.in1;
        int y = e.in2;


        if(unionFind(x,y) && !thirdEdge(x,y)){

            newedges.add(e);



        }

        else{

        }

    }
}


 public int findParent(int i){
    if (parent[i] != i)
       return findParent(parent[i]);
    return parent[i];

}

public boolean unionFind(int x, int y){
     int xx = findParent(x);
     int yy = findParent(y);

    if(xx == yy){

            if(subsize[xx]== n){
                donepath = true;
                return true;
            }
            return false;
    }
     else{

        if( subsize[xx] < subsize[yy]){
             parent[xx] = yy;
                              subsize[yy]+=subsize[xx];
         }
        else if( subsize[xx] >  subsize[yy]){
             parent[yy] = xx;  subsize[xx]+=subsize[yy];
         }
         else{
             parent[yy] = xx;
             subsize[xx]+=subsize[yy];
         } 
        connection[x]++;
        connection[y]++;

     }


    return true;


}

public boolean makesCycle(int x, int y){
        int xx = findParent(x);
        int yy = findParent(y);

        if(xx == yy){

            return true;
        }

    return false;
}

Here are the edges it goes through in order

0-0,
1-1,
2-2,
3-3,
4-4,
0-4 should get added,
2-3 should get added,
3-2,
4-0,
0-1 should get added,
0-2 ,
0-3,
1-0,
1-4,
2-0,
3-0,
4-1,
1-3 should get added,
3-1,
2-4 should get added......but doesnt,
3-4,
4-2,
4-3,
1-2,
2-1,
Was it helpful?

Solution

What about keeping track of the size of each of the sets?

Then, when doing a union, if the root of both is the same (i.e. a cycle) and the root's size equals the sum of all the points in your problem, include that edge and stop, otherwise continue as per usual.

Warning:

Note that a simple Union-Find implementation is likely to end you up with minimum spanning tree rather than a hamiltonian cycle. You need to make sure you pick appropriate edges - I'll assume you've figured that out, or, if not, I'll leave it to you.

Elaboration:

The Union for your problem should look something like: (derived from Wikipedia)
(returning false or true to indicate whether we should add the edge)

boolean Union(x, y)
   xRoot = Find(x)
   yRoot = Find(y)
   if xRoot == yRoot
      return false
   // merge xRoot and yRoot
   xRoot.parent = yRoot
   return true

(the proper merge (for efficiency) is a little more complicated - you should compare the depths and pick the deepest one as the parent, see Wikipedia for details)

Now, my suggestion:

Create a size variable for each node, initialized to 1, and then the Union function:

boolean Union(x, y)
   xRoot = Find(x)
   yRoot = Find(y)

   if xRoot == yRoot
      // check if it's the last node
      if xRoot.size == pointCount
         done = true
         return true
      else
         return false

   // merge xRoot and yRoot
   xRoot.parent = yRoot
   yRoot.size += xRoot.size
   return true

Example:

Points:

1---2
|\  |
| \ |
|  \|
4---3

There are 4 points, thus pointCount = 4

Starting off: (size appears under node)

1  2  3  4
1  1  1  1

Union 1 and 2:

1  3  4
2  1  1
|
2
1

Union 3 and 2:

3  4
3  1
|
1
2
|
2
1

Union 3 and 1:

The common root is 3 (thus xRoot == yRoot is true) and xRoot.size(3) != pointCount(4), thus we return false (don't add the edge).

Union 3 and 4:

4
4
|
3
3
|
1
2
|
2
1

Union 4 and 1:

The common root is 4 (thus xRoot == yRoot is true) and xRoot.size(4) == pointCount(4), thus we return true (add the edge) and we set the flag to indicate that we're done.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top