Mst oriented in O(NM)
This commit is contained in:
parent
b944df81ba
commit
27db1f5e06
3 changed files with 220 additions and 0 deletions
6
algo/mst_oriented/01.in
Normal file
6
algo/mst_oriented/01.in
Normal file
|
@ -0,0 +1,6 @@
|
|||
5 5 0
|
||||
0 1 5
|
||||
0 2 3
|
||||
2 3 2
|
||||
3 4 2
|
||||
4 2 2
|
12
algo/mst_oriented/02.in
Normal file
12
algo/mst_oriented/02.in
Normal file
|
@ -0,0 +1,12 @@
|
|||
9 11 0
|
||||
0 1 4
|
||||
2 6 4
|
||||
1 2 3
|
||||
2 3 3
|
||||
3 4 3
|
||||
4 5 3
|
||||
5 1 3
|
||||
4 7 1
|
||||
7 5 1
|
||||
5 4 1
|
||||
7 8 2
|
202
algo/mst_oriented/mst_oriented.cpp
Normal file
202
algo/mst_oriented/mst_oriented.cpp
Normal file
|
@ -0,0 +1,202 @@
|
|||
#include <bits/stdc++.h>
|
||||
|
||||
#define FOR(i, n) for(lli i = 0; i < (lli)(n); ++i)
|
||||
|
||||
#define X(A) get<0>(A)
|
||||
#define Y(A) get<1>(A)
|
||||
#define Z(A) get<2>(A)
|
||||
#define W(A) get<3>(A)
|
||||
|
||||
#define mt make_tuple
|
||||
|
||||
using namespace std;
|
||||
using lli = long long int;
|
||||
|
||||
using pii = tuple<lli, lli>;
|
||||
using piii = tuple<lli, lli, lli>;
|
||||
using vi = vector<lli>;
|
||||
using vii = vector<pii>;
|
||||
using viii = vector<piii>;
|
||||
using vvi = vector<vi>;
|
||||
using vvii = vector<vii>;
|
||||
using vviii = vector<viii>;
|
||||
using vb = vector<bool>;
|
||||
using vvb = vector<vb>;
|
||||
|
||||
/** WARNING **
|
||||
*************
|
||||
|
||||
This algorithm considers the graph to have no self-pointing edge, ie. no edge
|
||||
(u, u)
|
||||
*/
|
||||
|
||||
const int INFTY = 1000*1000*1000; // FIXME large enough for this problem?
|
||||
|
||||
struct Edge {
|
||||
int from, to;
|
||||
int weight;
|
||||
Edge() {}
|
||||
Edge(int from, int to, int weight): from(from), to(to), weight(weight) {}
|
||||
};
|
||||
|
||||
struct Vert {
|
||||
int selfId;
|
||||
int ufFather;
|
||||
int ufHeight;
|
||||
vector<int> out;
|
||||
vector<int> in;
|
||||
int parentEdge;
|
||||
bool suppressed;
|
||||
|
||||
Vert(int id):
|
||||
selfId(id), ufFather(id), ufHeight(1),
|
||||
parentEdge(-1), suppressed(false)
|
||||
{}
|
||||
};
|
||||
|
||||
int root;
|
||||
vector<Edge> edges;
|
||||
vector<Vert> vertices;
|
||||
int cost = 0;
|
||||
|
||||
int ufFind(int vert) {
|
||||
Vert& v = vertices[vert];
|
||||
if(v.ufFather == vert)
|
||||
return vert;
|
||||
v.ufFather = ufFind(v.ufFather);
|
||||
return v.ufFather;
|
||||
}
|
||||
|
||||
void ufUnion(int iv1, int iv2) {
|
||||
iv1 = ufFind(iv1);
|
||||
iv2 = ufFind(iv2);
|
||||
Vert& v1 = vertices[iv1];
|
||||
Vert& v2 = vertices[iv2];
|
||||
if(v1.ufHeight < v2.ufHeight)
|
||||
v1.ufFather = iv2;
|
||||
else if(v2.ufHeight < v1.ufHeight)
|
||||
v2.ufFather = iv1;
|
||||
else {
|
||||
v1.ufFather = iv2;
|
||||
v2.ufHeight++;
|
||||
}
|
||||
}
|
||||
|
||||
void buildMst(int vertId) {
|
||||
printf("> %d\n", vertId);
|
||||
Vert& vert = vertices[vertId];
|
||||
int minIncWeight = INFTY;
|
||||
int minId = -1;
|
||||
|
||||
for(int incEdge: vert.in) {
|
||||
Edge& edge = edges[incEdge];
|
||||
if(minIncWeight > edge.weight) {
|
||||
minIncWeight = edge.weight;
|
||||
minId = incEdge;
|
||||
}
|
||||
}
|
||||
|
||||
if(minId == -1) {
|
||||
assert(vertId == root);
|
||||
return;
|
||||
}
|
||||
|
||||
for(int incEdge: vert.in) {
|
||||
Edge& edge = edges[incEdge];
|
||||
edge.weight -= minIncWeight;
|
||||
}
|
||||
cost += minIncWeight;
|
||||
|
||||
vert.parentEdge = minId;
|
||||
int parent = edges[minId].from;
|
||||
int parentCmp = ufFind(parent), selfCmp = ufFind(vertId);
|
||||
if(parentCmp == selfCmp) {
|
||||
// Build current cycle
|
||||
vector<int> cycle;
|
||||
cycle.push_back(parent);
|
||||
while(cycle.back() != vertId)
|
||||
cycle.push_back(edges[vertices[cycle.back()].parentEdge].from);
|
||||
|
||||
vertices.push_back(Vert(vertices.size()));
|
||||
Vert& condensed = vertices.back();
|
||||
printf("Compressing into %d: ", condensed.selfId);
|
||||
for(int cyc: cycle)
|
||||
printf("%d ", cyc);
|
||||
puts("");
|
||||
vector<int> nInEdges, nOutEdges;
|
||||
for(int cycleVert: cycle) {
|
||||
Vert& v = vertices[cycleVert];
|
||||
v.suppressed = true;
|
||||
for(int inEdge: v.in) {
|
||||
edges[inEdge].to = condensed.selfId;
|
||||
nInEdges.push_back(inEdge);
|
||||
}
|
||||
for(int outEdge: v.out) {
|
||||
edges[outEdge].from = condensed.selfId;
|
||||
if(edges[outEdge].to != condensed.selfId)
|
||||
condensed.out.push_back(outEdge);
|
||||
}
|
||||
}
|
||||
|
||||
for(int inEdge: nInEdges) {
|
||||
if(edges[inEdge].from != condensed.selfId)
|
||||
condensed.in.push_back(inEdge);
|
||||
}
|
||||
|
||||
ufUnion(vertId, condensed.selfId);
|
||||
buildMst(condensed.selfId);
|
||||
}
|
||||
else {
|
||||
ufUnion(vertId, parent);
|
||||
if(ufFind(vertId) != ufFind(root))
|
||||
buildMst(parent);
|
||||
}
|
||||
}
|
||||
|
||||
void dfs(int pos, vector<bool>& seen) {
|
||||
if(seen[pos])
|
||||
return;
|
||||
seen[pos] = true;
|
||||
for(int outEdge: vertices[pos].out)
|
||||
dfs(edges[outEdge].to, seen);
|
||||
}
|
||||
|
||||
bool allReachable() {
|
||||
vector<bool> seen(vertices.size(), false);
|
||||
dfs(root, seen);
|
||||
for(size_t pos=0; pos < seen.size(); ++pos) {
|
||||
if(!seen[pos]) {
|
||||
fprintf(stderr, "NOT REACHABLE: %lu\n", pos);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int main() {
|
||||
int nbVert, nbEdge;
|
||||
scanf("%d%d%d", &nbVert, &nbEdge, &root);
|
||||
for(int vert=0; vert < nbVert; ++vert)
|
||||
vertices.push_back(Vert(vert));
|
||||
for(int edgeId=0; edgeId < nbEdge; ++edgeId) {
|
||||
Edge edge;
|
||||
scanf("%d%d%d", &edge.from, &edge.to, &edge.weight);
|
||||
edges.push_back(edge);
|
||||
vertices[edge.from].out.push_back(edges.size() - 1);
|
||||
vertices[edge.to].in.push_back(edges.size() - 1);
|
||||
}
|
||||
|
||||
if(!allReachable()) {
|
||||
printf("-1\n");
|
||||
puts("BLEH");
|
||||
return 0;
|
||||
}
|
||||
|
||||
for(int vert=0; vert < nbVert; ++vert) {
|
||||
if(vertices[vert].suppressed || ufFind(vert) == root)
|
||||
continue;
|
||||
buildMst(vert);
|
||||
}
|
||||
|
||||
printf("%d\n", cost);
|
||||
}
|
Loading…
Reference in a new issue