kopia lustrzana https://github.com/jameshball/osci-render
150 wiersze
3.9 KiB
C
150 wiersze
3.9 KiB
C
#include "Dijkstra.h"
|
|
#include "./Matching.h"
|
|
#include "./Graph.h"
|
|
|
|
bool Connected(Graph & G)
|
|
{
|
|
vector<bool> visited(G.GetNumVertices(), false);
|
|
list<int> L;
|
|
|
|
int n = 0;
|
|
L.push_back(0);
|
|
while(not L.empty())
|
|
{
|
|
int u = L.back();
|
|
L.pop_back();
|
|
if(visited[u]) continue;
|
|
|
|
visited[u] = true;
|
|
n++;
|
|
|
|
for(int v : G.AdjList(u)) {
|
|
L.push_back(v);
|
|
}
|
|
}
|
|
|
|
return G.GetNumVertices() == n;
|
|
}
|
|
|
|
/*
|
|
Solves the chinese postman problem
|
|
returns a pair containing a list and a double
|
|
the list is the sequence of vertices in the solution
|
|
the double is the solution cost
|
|
*/
|
|
pair< list<int>, double > ChinesePostman(Graph& G, vector<double>& cost)
|
|
{
|
|
//Check if the graph if connected
|
|
if(not Connected(G))
|
|
throw "Error: Graph is not connected";
|
|
|
|
//Build adjacency lists using edges in the graph
|
|
vector<vector<int>> A(G.GetNumVertices(), vector<int>());
|
|
for(int u = 0; u < G.GetNumVertices(); u++)
|
|
A[u] = G.AdjList(u);
|
|
|
|
//Find vertices with odd degree
|
|
vector<int> odd;
|
|
for(int u = 0; u < G.GetNumVertices(); u++)
|
|
if(A[u].size() % 2)
|
|
odd.push_back(u);
|
|
|
|
//If there are odd degree vertices
|
|
if(not odd.empty())
|
|
{
|
|
//Create a graph with the odd degree vertices
|
|
auto edges = list<pair<int, int>>();
|
|
Graph O(odd.size(), edges);
|
|
for(int u = 0; u < (int)odd.size(); u++)
|
|
for(int v = u+1; v < (int)odd.size(); v++)
|
|
O.AddEdge(u, v);
|
|
|
|
vector<double> costO(O.GetNumEdges());
|
|
|
|
//Find the shortest paths between all odd degree vertices
|
|
vector< vector<int> > shortestPath(O.GetNumVertices());
|
|
for(int u = 0; u < (int)odd.size(); u++)
|
|
{
|
|
pair< vector<int>, vector<double> > sp = Dijkstra(G, odd[u], cost);
|
|
|
|
shortestPath[u] = sp.first ;
|
|
|
|
//The cost of an edge uv in O will be the cost of the corresponding shortest path in G
|
|
for(int v = 0; v < (int)odd.size(); v++)
|
|
if(v != u)
|
|
costO[ O.GetEdgeIndex(u, v) ] = sp.second[odd[v]];
|
|
}
|
|
|
|
//Find the minimum cost perfect matching of the graph of the odd degree vertices
|
|
Matching M(O);
|
|
pair< list<int>, double > p = M.SolveMinimumCostPerfectMatching(costO);
|
|
list<int> matching = p.first;
|
|
|
|
//If an edge uv is in the matching, the edges in the shortest path from u to v should be duplicated in G
|
|
for(list<int>::iterator it = matching.begin(); it != matching.end(); it++)
|
|
{
|
|
pair<int, int> p = O.GetEdge(*it);
|
|
int u = p.first, v = odd[p.second];
|
|
|
|
//Go through the path adding the edges
|
|
int w = shortestPath[u][v];
|
|
while(w != -1)
|
|
{
|
|
A[w].push_back(v);
|
|
A[v].push_back(w);
|
|
v = w;
|
|
w = shortestPath[u][v];
|
|
}
|
|
}
|
|
}
|
|
|
|
//Find an Eulerian cycle in the graph implied by A
|
|
list<int> cycle;
|
|
//This is to keep track of how many times we can traverse an edge
|
|
vector<int> traversed(G.GetNumEdges(), 0);
|
|
for(int u = 0; u < G.GetNumVertices(); u++)
|
|
{
|
|
for(int v : A[u]) {
|
|
//we do this so that the edge is not counted twice
|
|
if(v < u) continue;
|
|
|
|
traversed[G.GetEdgeIndex(u, v)]++;
|
|
}
|
|
}
|
|
|
|
cycle.push_back(0);
|
|
list<int>::iterator itp = cycle.begin();
|
|
double obj = 0;
|
|
while(itp != cycle.end())
|
|
{
|
|
//Let u be the current vertex in the cycle, starting at the first
|
|
int u = *itp;
|
|
list<int>::iterator jtp = itp;
|
|
jtp++;
|
|
|
|
//if there are non-traversed edges incident to u, find a subcycle starting at u
|
|
//replace u in the cycle by the subcycle
|
|
while(not A[u].empty())
|
|
{
|
|
while(not A[u].empty() and traversed[ G.GetEdgeIndex(u, A[u].back()) ] == 0)
|
|
A[u].pop_back();
|
|
|
|
if(not A[u].empty())
|
|
{
|
|
int v = A[u].back();
|
|
A[u].pop_back();
|
|
cycle.insert(jtp, v);
|
|
traversed[G.GetEdgeIndex(u, v)]--;
|
|
|
|
obj += cost.empty() ? 1.0 : cost[ G.GetEdgeIndex(u, v) ];
|
|
u = v;
|
|
}
|
|
}
|
|
|
|
//go to the next vertex in the cycle and do the same
|
|
itp++;
|
|
}
|
|
|
|
return pair< list<int>, double >(cycle, obj);
|
|
}
|