Run Time: 0.030
Ranking (as of 2016-07-06): 25 out of 268
Language: C++
/*
UVa 12144 - Almost Shortest Path
To build using Visual Studio 2012:
cl -EHsc -O2 UVa_12144_Almost_Shortest_Path.cpp
*/
#include <vector>
#include <set>
#include <queue>
#include <utility>
#include <limits>
#include <cstdio>
using namespace std;
const int infinite = numeric_limits<int>::max();
const int N_max = 500;
struct edge {
int v_;
int w_;
bool removed_;
edge(int v, int w) : v_(v), w_(w), removed_(false) {}
};
vector<edge> edges[N_max];
int distances[N_max];
bool visited[N_max];
vector< pair<int, int> > paths[N_max];
struct distance_comparator {
bool operator() (int i, int j) const
{
return (distances[i] != distances[j]) ? distances[i] < distances[j] : i < j;
}
};
int shortest_path(int n, int start, int end)
{
for (int i = 0; i < n; i++)
visited[i] = false, distances[i] = infinite, paths[i].clear();
set<int, distance_comparator> pq; // priority queue
int min_d = -1;
distances[start] = 0;
pq.insert(start);
while(!pq.empty()) {
int u = *pq.begin();
pq.erase(pq.begin());
visited[u] = true;
int d = distances[u];
#ifdef DEBUG
printf("%d: %d\n", u, d);
#endif
if (u == end)
min_d = d;
else {
const vector<edge>& es = edges[u];
for (int i = 0, j = static_cast<int>(es.size()); i < j; i++) {
int v = es[i].v_, w = es[i].w_;
if (!visited[v] && distances[v] > d + w) {
pq.erase(v); // remove v if it has already been in the queue
distances[v] = d + w;
paths[v].clear();
paths[v].push_back(make_pair(u, i));
#ifdef DEBUG
printf("\t%d-%d\n", u, v);
#endif
pq.insert(v);
}
else if (distances[v] == d + w) {
paths[v].push_back(make_pair(u, i));
#ifdef DEBUG
printf("\t%d-%d\n", u, v);
#endif
}
}
}
}
return min_d;
}
void mark_shortest_paths(int n, int end)
{
for (int i = 0; i < n; i++)
visited[i] = false;
queue<int> q;
visited[end] = true;
q.push(end);
while (!q.empty()) {
int u = q.front();
q.pop();
vector< pair<int, int> >& ps = paths[u];
for (int i = 0, j = static_cast<int>(ps.size()); i < j; i++) {
int v = ps[i].first;
#ifdef DEBUG
printf("%d-%d\n", v, edges[v][ps[i].second].v_);
#endif
edges[v][ps[i].second].removed_ = true;
if (!visited[v]) {
visited[v] = true;
q.push(v);
}
}
}
}
int allmost_shortest_path(int n, int start, int end)
{
for (int i = 0; i < n; i++)
visited[i] = false, distances[i] = infinite;
set<int, distance_comparator> pq; // priority queue
distances[start] = 0;
pq.insert(start);
while(!pq.empty()) {
int u = *pq.begin();
pq.erase(pq.begin());
visited[u] = true;
int d = distances[u];
if (u == end)
return d;
const vector<edge>& es = edges[u];
for (size_t i = 0, j = es.size(); i < j; i++) {
if (es[i].removed_)
continue;
int v = es[i].v_, w = es[i].w_;
if (!visited[v] && distances[v] > d + w) {
pq.erase(v); // remove v if it has already been in the queue
distances[v] = d + w;
pq.insert(v);
}
}
}
return -1;
}
int main()
{
while (true) {
int N, M;
scanf("%d %d", &N, &M);
if (!N)
break;
for (int i = 0; i < N; i++)
edges[i].clear();
int S, D;
scanf("%d %d", &S, &D);
while (M--) {
int U, V, P;
scanf("%d %d %d", &U, &V, &P);
edges[U].push_back(edge(V, P));
}
int d = shortest_path(N, S, D);
#ifdef DEBUG
printf("%d\n", d);
#endif
if (d != -1) {
mark_shortest_paths(N, D);
d = allmost_shortest_path(N, S, D);
}
printf("%d\n", d);
}
return 0;
}
No comments:
Post a Comment