00001
00002
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
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
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
00063
00064
00065 int * first_on_chain = new int[n];
00066 int * last_on_chain = new int[n];
00067
00068 int * next_on_chain = new int[n];
00069
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;
00082 int label_l = -1;
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
00100
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
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 }