洛谷P2901
Description
BESSIE准备用从牛棚跑到池塘的方法来锻炼. 但是因为她懒,她只准备沿着下坡的路跑到池塘, 然后走回牛棚. BESSIE也不想跑得太远,所以她想走最短的路经. 农场上一共有M (1 <= M <= 10,000)条路, 每条路连接两个用1..N(1 <= N <= 1000)标号的地点. 更方便的是,如果X>Y,则地点X的高度大于地点Y的高度. 地点N是BESSIE的牛棚;地点1是池塘. 很快, BESSIE厌倦了一直走同一条路.所以她想走不同的路,更明确地讲,她想找出K (1 <= K <= 100)条不同的路经.为了避免过度劳累,她想使这K条路经为最短的K条路经. 请帮助BESSIE找出这K条最短路经的长度.你的程序需要读入农场的地图, 一些从X_i到Y_i 的路经和它们的长度(X_i, Y_i, D_i). 所有(X_i, Y_i, D_i)满足(1 <= Y_i < X_i; Y_i < X_i <= N, 1 <= D_i <= 1,000,000).
Input
* 第1行: 3个数: N, M, 和K
* 第 2..M+1行: 第 i+1 行包含3个数 X_i, Y_i, 和 D_i, 表示一条下坡的路.
Output
* 第1..K行: 第i行包含第i最短路经的长度,或-1如果这样的路经不存在.如果多条路经有同样的长度,请注意将这些长度逐一列出.
Sample Input
5 8 7 5 4 1 5 3 1 5 2 1 5 1 1 4 3 4 3 1 1 3 2 1 2 1 1
Sample Output
1 2 2 3 6 7 -1 //路经分别为(5-1), (5-3-1), (5-2-1), (5-3-2-1), (5-4-3-1),(5-4-3-2-1).
分析
这个题是一个k短路的板子题,只需要在找到每条路径时记录一下就好
在建图的时候,我们可以反向再建一张图,然后用反向建出来的这张图求出每个节点到终点的最短路,也就是说把终点 t 看成起点求它与每个节点的最短路径。
然后从起点s到终点t的路径就变成了从s到当前节点 + 从当前节点到t,因为后者我们已经算出来了,所以只需要正向跑一个最短路,同时使用一个启发式函数,每找到一条路径就将它保存下来,最后输出就ok了
代码
#include
using namespace std;
struct edge {
int v, w, next;
} e[100010], e1[100010];
int head[1010], head1[1010], cnt;
int n, m, k;
int dis[1010];
bool vis[1010];
inline int read() {
int x = 0, f = 1; char ch = getchar();
while (ch < '0' || ch > '9') {if (ch == '-') f = -1; ch = getchar();}
while (ch >= '0' && ch <= '9') {x = (x << 1) + (x << 3) + (ch ^ 48); ch = getchar();}
return x * f;
}
void insert(int u, int v, int w) {
e[++cnt].v = v, e[cnt].w = w, e[cnt].next = head[u], head[u] = cnt;
e1[cnt].v = u, e1[cnt].w = w, e1[cnt].next = head1[u], head1[u] = cnt;
//反向建图
}
void spfa() {
memset(dis, 1e9, sizeof dis);
queue q;
dis[n] = 0;
vis[n] = 1;
q.push(n);
int u;
while (!q.empty()) {
u = q.front();
q.pop();
vis[u] = false;
for (int i = head1[u]; i; i = e1[i].next) {
int v = e1[i].v, w = e1[i].w;
if (dis[v] > dis[u] + w) {
dis[v] = dis[u] + w;
if (!vis[v]) {
vis[v] = true;
q.push(v);
}
}
}
}
}
struct node {
int d, id;
node () {}
node (int dd, int di) {
d = dd;
id = di;
}
bool operator < (const node & x) const {
return x.d < d;
}
};
int ans[110], kk;
priority_queue q;
void A_star() {
q.push(node(dis[n], n));
while (!q.empty()) {
int d = q.top().d, num = q.top().id;
q.pop();
if (num == 1) {
ans[++kk] = d;
if (kk == k) return;
}
for (int i = head[num]; i; i = e[i].next) {
q.push(node(d - dis[num] + e[i].w + dis[e[i].v], e[i].v));
}
}
}
int main() {
n = read(), m = read(), k = read();
for (int i = 1; i <= m; i++) {
int u = read(), v = read(), w = read();
insert(u, v, w);
}
spfa();
A_star();
for (int i = 1; i <= k; i++) {
if (ans[i]) printf("%d\n", ans[i]);
else puts("-1");
}
return 0;
}