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;
}
-------------------------------------------------------
kedebug
Department of Computer Science and Engineering,
Shanghai Jiao Tong University
E-mail: kedebug0@gmail.com
GitHub: http://github.com/kedebug
-------------------------------------------------------