/home/coin/SVN-release/OS-2.4.0/Bcp/examples/MaxCut/Member/MC_kruskal.cpp

Go to the documentation of this file.
00001 // Copyright (C) 2000, International Business Machines
00002 // Corporation and others.  All Rights Reserved.
00003 #include <cassert>
00004 #include <algorithm>
00005 #include <numeric>
00006 
00007 #include "CoinHelperFunctions.hpp"
00008 
00009 #include "MC_cut.hpp"
00010 #include "MC.hpp"
00011 
00012 //#############################################################################
00013 
00014 static void
00015 MC_label_neighbors(const int this_node, const int* degree,
00016                    const int* neighbornode, const int* neighboredge,
00017                    int * parentnode, int * parentedge)
00018 {
00019   for (int i = degree[this_node]; i < degree[this_node+1]; ++i) {
00020     const int child = neighbornode[i];
00021     if (parentnode[child] == -2) {
00022       parentnode[child] = this_node;
00023       parentedge[child] = neighboredge[i];
00024       MC_label_neighbors(child, degree, neighbornode, neighboredge,
00025                          parentnode, parentedge);
00026     }
00027   }
00028 }
00029 
00030 //#############################################################################
00031 
00032 void
00033 MC_kruskal(const MC_problem& mc, const int* edgeorder, const double* x,
00034            int * nodesign, int * edges_in_tree)
00035 {
00036   //--------------------------------------------------------------------------
00037   // Kruskal's algo is used (the version when we add edges starting from the
00038   // cheapest and never creating a cycle). Avoiding cycles is ensured by
00039   // keeping the components in chains (first each in its own chain), later
00040   // an edge is added iff its two endpoints have different chain heads.
00041   //
00042   // NOTE: the weights on the edges are not needed to find the MST, it's
00043   // enough that the edges are ordered in increasing weight.
00044   // HOWEVER, to fill out nodesign we need the weights (or it might be a
00045   // different vector...).
00046   //--------------------------------------------------------------------------
00047 
00048   // Also, create the nodesign array: mark the tree nodes with +/- 1 according
00049   // to the following rule: if the x value of the edge is closer to 0 then the
00050   // two nodes are on the same side, if it's closer to 1 then they are on the
00051   // opposite sides. This is done by assigning +1 to each node to start with,
00052   // and when two chains are merged (the shorted appended to the longer) the
00053   // nodesigns of all nodes on the shorter chain are reversed if necessary.
00054   // nodesign is assumed to be exactly mc.num_nodes long.
00055 
00056   const int n = mc.num_nodes;
00057   const int m = mc.num_edges;
00058   int k;
00059 
00060   CoinFillN(nodesign, n, 1);
00061 
00062   // the first/last node on the chain containing the i-th node
00063   // first_on_chain is accurate for every i,
00064   // last_on_chain is accurate only for chain heads!
00065   int * first_on_chain = new int[n];
00066   int * last_on_chain  = new int[n];
00067   // the next node in the same chain, or -1 if there aren't more. ACCURATE
00068   int * next_on_chain  = new int[n];
00069   // size of the chain containing i. Accurate only for chain heads!
00070   int * size_of_chain  = new int[n];
00071 
00072   CoinIotaN(first_on_chain, n, 0);
00073   CoinIotaN(last_on_chain, n, 0);
00074   CoinFillN(next_on_chain, n, -1);
00075   CoinFillN(size_of_chain, n, 1);
00076 
00077   int tree_size = 0;
00078 
00079   const MC_graph_edge* edges = mc.edges;
00080 
00081   int label_s = -1; // shorter chain head
00082   int label_l = -1; // longer chain head
00083   for (k = 0; k < m; ++k) {
00084     const int kth_edge = edgeorder[k];
00085     const int i = edges[kth_edge].tail;
00086     const int j = edges[kth_edge].head;
00087     const int label_i = first_on_chain[i];
00088     const int label_j = first_on_chain[j];
00089     if (label_i == label_j)
00090       continue;
00091     if (size_of_chain[label_i] > size_of_chain[label_j]) {
00092       label_s = label_j;
00093       label_l = label_i;
00094     } else {
00095       label_s = label_i;
00096       label_l = label_j;
00097     }
00098     edges_in_tree[tree_size++] = kth_edge;
00099     // relabel those in the chain headed by label_s and if necessary, reverse
00100     // the nodesign of all of them 
00101     for (int l = label_s; l != -1; l = next_on_chain[l]) {
00102       first_on_chain[l] = label_l;
00103     }
00104     if ((x[kth_edge] > .5 && (nodesign[i] == nodesign[j])) ||
00105         (x[kth_edge] < .5 && (nodesign[i] != nodesign[j])) ) {
00106       for (int l = label_s; l != -1; l = next_on_chain[l]) {
00107         nodesign[l] = -nodesign[l];
00108       }
00109     }
00110     next_on_chain[last_on_chain[label_l]] = label_s;
00111     last_on_chain[label_l] = last_on_chain[label_s];
00112     size_of_chain[label_l] += size_of_chain[label_s];
00113   }
00114 
00115   if (tree_size != n-1) {
00116     printf("MC: The MST has less than n-1 edges!\n");
00117     abort();
00118   }
00119 
00120   delete[] size_of_chain;
00121   delete[] next_on_chain;
00122   delete[] last_on_chain;
00123   delete[] first_on_chain;
00124 }
00125 
00126 //#############################################################################
00127 
00128 void
00129 MC_kruskal(const MC_problem& mc, const int * edgeorder, const double* x,
00130            int * nodesign, int * parentnode, int * parentedge)
00131 {
00132   const int n = mc.num_nodes;
00133 
00134   int * edges_in_tree = new int[n-1];
00135 
00136   MC_kruskal(mc, edgeorder, x, nodesign, edges_in_tree);
00137 
00138   // Create the rooted tree
00139 
00140   int * neighbornode   = new int[2*n];
00141   int * neighboredge   = new int[2*n];
00142   int * degree         = new int[n+1];
00143 
00144   int k;
00145   const int tree_size = n - 1;
00146   const MC_graph_edge* edges = mc.edges;
00147 
00148   CoinFillN(degree, n + 1, 0);
00149   for (k = 0; k < tree_size; ++k) {
00150     const int l = edges_in_tree[k];
00151     ++degree[edges[l].tail];
00152     ++degree[edges[l].head];
00153   }
00154   const int maxdeg_node = std::max_element(degree, degree + n) - degree;
00155 
00156   std::partial_sum(degree, degree + n, degree);
00157   degree[n] = 0;
00158   std::rotate(degree, degree + n, degree + (n+1));
00159 
00160   for (k = 0; k < tree_size; ++k) {
00161     const int l = edges_in_tree[k];
00162     const int i = edges[l].tail;
00163     const int j = edges[l].head;
00164     neighbornode[degree[i]] = j;
00165     neighbornode[degree[j]] = i;
00166     neighboredge[degree[i]++] = l;
00167     neighboredge[degree[j]++] = l;
00168   }
00169   std::rotate(degree, degree + n, degree + (n+1));
00170   degree[0] = 0;
00171 
00172   CoinFillN(parentnode, n, -2);
00173   CoinFillN(parentedge, n, -1);
00174   parentnode[maxdeg_node] = -1;
00175   MC_label_neighbors(maxdeg_node, degree, neighbornode, neighboredge,
00176                      parentnode, parentedge);
00177 
00178   delete[] degree;
00179   delete[] neighboredge;
00180   delete[] neighbornode;
00181   delete[] edges_in_tree;
00182 }

Generated on Thu Sep 22 03:05:51 2011 by  doxygen 1.4.7