0

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,
Bernhard Barker
  • 54,589
  • 14
  • 104
  • 138
Teddy Black
  • 193
  • 2
  • 14

1 Answers1

1

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.

Bernhard Barker
  • 54,589
  • 14
  • 104
  • 138
  • what about stopping unwanted cycles? – Teddy Black Oct 13 '13 at 18:08
  • You already have cycle detection, this should still be done in the "continue as per normal" part. – Bernhard Barker Oct 13 '13 at 18:10
  • not sure if its that easy. Maybe its the way i implemented it. Could you give me an example of how I would do that? – Teddy Black Oct 13 '13 at 19:50
  • its just not working right. It still messes up when I get to the one edge that should end it all. I'll post my code. – Teddy Black Oct 14 '13 at 03:01
  • I did it like you suggested at first, still didnt work out, so i kept tweaking and just blew up the world..... – Teddy Black Oct 14 '13 at 03:07
  • @TeddyBlack Where you've got `subsize[xx]+=subsize[yy];`, you should also add `subsize[xx]+=subsize[yy];` and `subsize[yy]+=subsize[xx];` to the two if-statements before it (the size of a node should be changed whenever you assign a child to it). And `makesCycle` shouldn't be there - it will cause it to never call `unionFind` for the last edge - `unionFind` takes care of the cycle check. And make sure you initialize all elements of `subsize` to `1`. – Bernhard Barker Oct 14 '13 at 08:23
  • changed what you said...finds even less edges now. What am I doing wrong. Edited the code up top. – Teddy Black Oct 14 '13 at 14:33
  • @TeddyBlack It should be `if(unionFind(x,y) && !thirdEdge(x,y)){` (note that I removed the `!` at the beginning). Also, what does `thirdEdge` do? – Bernhard Barker Oct 14 '13 at 14:37
  • part of the requirment was that it shouldnt add an edge that would be the third edge from any vertex. This is to stop it from adding 0-4, 0-1, then adding 0-2 after that, which would make the problem unsolvable. – Teddy Black Oct 14 '13 at 14:39
  • all it does is check connection[x] and connection[y] if either of those are >=2, then dont add the edge. If you notice, in union I increase connection everytime i add an egde. Also, it still doesnt work. Now its only adding 0-4 and 2-3 – Teddy Black Oct 14 '13 at 15:09
  • @TeddyBlack The code you provided looks right, thus my guess is that `parent`, `connection` or `subsize` is not initialized correctly (it should be: each `parent[i] = i` and each `subsize[i] = 1` and each `connection[i] = 0`), or there's a bug in `thirdEdge`. My suggestion is to add a few print statements so you can see exactly what it's doing and which values it's updating with what. Or you can provide the rest of the code (in form of an [SSCCE](http://sscce.org/), so I can run it), though me pointing out your mistake will teach you a lot less than you figuring it out yourself. – Bernhard Barker Oct 14 '13 at 15:39
  • wow....I got it to work. It was thirdangle, but not because it was doing anything wrong, it was that since I had (unionFind(x,y) && !thirdangle(x,y)), it would check unionFind first, would end up adding an edge anyway, before checking if it could do so due to third edge, so when it got to third edge the connections were already increased based 3 and everything fell from there. All I had to do was switch those around -_-. I can't thank you enough for your help. THANK YOU!!!!!!!!!!!! – Teddy Black Oct 14 '13 at 17:55