POJ 3463 Sightseeing(次短路问题)

题意:

给定一张有向图,求最短路的条数,如果次短路长度 = 最短路 + 1,则输出最短路和次短路条数的和。

思路:

1. 一开始想到 POJ 2449 求 k 短路的方法求解,case 都过的差不多了,无奈 TLE 了,于是找到题解,求最短路的过程中顺带求出次短路;

2. 分别设置二维数组 d[0][i] 表示 s 到 i 的最短路,d[1][i] 表示 s 到 i 的次短路,cnt[][] , vis[][] 数组都是类似的;

3. 依然有地方需要注意的是,当更新某一点最短路/次短路的时候,计数的数组要赋值为其父节点引向其的技术值,具体见代码;

 

// 方法 1 (dijkstra 47ms)
#include
<iostream> #include <algorithm> #include <queue> #include <vector> using namespace std; const int MAXN = 1010; const int INFS = 0x3FFFFFFF; struct edge { int to, cost; edge(int _to, int _cost) : to(_to), cost(_cost) {} }; vector<edge> G[MAXN]; int d[2][MAXN], cnt[2][MAXN]; bool vis[2][MAXN]; struct ST { int u, dd, r; ST(int _u, int _dd, int _r) : u(_u), dd(_dd), r(_r) {} bool operator < (const ST& o) const { return dd > o.dd; } }; int dijkstra(int s, int t, int n) { for (int i = 1; i <= n; i++) { d[0][i] = d[1][i] = INFS; cnt[0][i] = cnt[1][i] = 0; vis[0][i] = vis[1][i] = false; } priority_queue<ST> Q; Q.push(ST(s, 0, 0)); d[0][s] = 0, cnt[0][s] = 1; while (!Q.empty()) { ST o = Q.top(); Q.pop(); int u = o.u, r = o.r; if (vis[r][u]) continue; else vis[r][u] = true; for (int i = 0; i < G[u].size(); i++) { edge& e = G[u][i]; int dis = o.dd + e.cost; if (dis < d[0][e.to]) { if (d[0][e.to] != INFS) { cnt[1][e.to] = cnt[0][e.to]; d[1][e.to] = d[0][e.to]; Q.push(ST(e.to, d[1][e.to], 1)); } d[0][e.to] = dis; cnt[0][e.to] = cnt[r][u]; Q.push(ST(e.to, dis, 0)); } else if (dis == d[0][e.to]) { cnt[0][e.to] += cnt[r][u]; } else if (dis < d[1][e.to]) { d[1][e.to] = dis; cnt[1][e.to] = cnt[r][u]; Q.push(ST(e.to, dis, 1)); } else if (dis == d[1][e.to]) { cnt[1][e.to] += cnt[r][u]; } } } int ans = cnt[0][t]; if (d[0][t] == d[1][t] - 1) ans += cnt[1][t]; return ans; } int main() { int cases; scanf("%d", &cases); while (cases--) { int n, m; scanf("%d%d", &n, &m); for (int i = 1; i <= n; i++) G[i].clear(); for (int i = 0; i < m; i++) { int u, v, cost; scanf("%d%d%d", &u, &v, &cost); G[u].push_back(edge(v, cost)); } int s, t; scanf("%d%d", &s, &t); printf("%d\n", dijkstra(s, t, n)); } return 0; }

// 方法 2:(K 短路解法 TLE
#include
<iostream> #include <algorithm> #include <vector> #include <queue> using namespace std; const int MAXN = 1010; const int INFS = 0x3FFFFFFF; struct edge { int to, cost; edge(int _to, int _cost) : to(_to), cost(_cost) {} }; struct ST { int u, cost, f; ST(int _u, int _cost, int _f) : u(_u), cost(_cost), f(_f) {} bool operator < (const ST& other) const { return f > other.f; } }; vector<edge> G[MAXN], P[MAXN]; int d[MAXN]; bool vis[MAXN]; void SPFA(int s, int n) { for (int i = 1; i <= n; i++) d[i] = INFS, vis[i] = false; queue<int> Q; Q.push(s); d[s] = 0, vis[s] = true; while (!Q.empty()) { int x = Q.front(); Q.pop(); vis[x] = false; for (int i = 0; i < P[x].size(); i++) { edge& e = P[x][i]; if (d[e.to] > d[x] + e.cost) { d[e.to] = d[x] + e.cost; if (!vis[e.to]) { vis[e.to] = true; Q.push(e.to); } } } } } int solve(int s, int t, int n) { priority_queue<ST> Q; Q.push(ST(s, 0, d[t])); int count = 0; bool flag = false; while (!Q.empty()) { ST o = Q.top(); Q.pop(); if (o.u == t) { if (o.cost == d[s]) count += 1; else if (o.cost == d[s] + 1) count += 1; else return count; } for (int i = 0; i < G[o.u].size(); i++) { edge& e = G[o.u][i]; Q.push(ST(e.to, e.cost + o.cost, e.cost + o.cost + d[e.to])); } } return count; } int main() { int cases; scanf("%d", &cases); while (cases--) { int n, m, s, t; scanf("%d%d", &n, &m); for (int i = 1; i <= n; i++) G[i].clear(), P[i].clear(); for (int i = 0; i < m; i++) { int u, v, cost; scanf("%d%d%d", &u, &v, &cost); G[u].push_back(edge(v, cost)); P[v].push_back(edge(u, cost)); } scanf("%d%d", &s, &t); SPFA(t, n); printf("%d\n", solve(s, t, n)); } return 0; }
posted @ 2013-04-27 20:28  kedebug  阅读(585)  评论(0编辑  收藏  举报