一、内容
For their physical fitness program, N (2 ≤ N ≤ 1,000,000) cows have decided to run a relay race using the T (2 ≤ T ≤ 100) cow trails throughout the pasture.
Each trail connects two different intersections (1 ≤ I1i ≤ 1,000; 1 ≤ I2i ≤ 1,000), each of which is the termination for at least two trails. The cows know the lengthi of each trail (1 ≤ lengthi ≤ 1,000), the two intersections the trail connects, and they know that no two intersections are directly connected by two different trails. The trails form a structure known mathematically as a graph.
To run the relay, the N cows position themselves at various intersections (some intersections might have more than one cow). They must position themselves properly so that they can hand off the baton cow-by-cow and end up at the proper finishing place.
Write a program to help position the cows. Find the shortest path that connects the starting intersection (S) and the ending intersection (E) and traverses exactly N cow trails.
Input
* Line 1: Four space-separated integers: N, T, S, and E
* Lines 2..T+1: Line i+1 describes trail i with three space-separated integers: lengthi , I1i , and I2i
Output
* Line 1: A single integer that is the shortest distance from intersection S to intersection E that traverses exactly N cow trails.
Sample Input
2 6 6 4
11 4 6
4 4 8
8 4 9
6 6 8
2 6 9
3 8 9
Sample Output
10
二、思路
- 题目叫求有刚好经过K条边,数据不打Bellman-ford应该能过。这里我们可以使用Floyd的思路。但是我们要改变d数组的含义了。Floyd求最短路时d[i][j] 代表i到j经过的点的编号不大于k的最短路径。 而这里是经过k条边的最短路径。
- d[k][i][j] : 代表i到j恰好经过k条边的最短路径。
- 转移方程: d[a+b][i][j] = min(d[a+b][i][j], d[a][i][k] + d[b][k][j]) 代表i到k经过了a条边,k到j经过b条边。
- d[1][i][j] --> d[2][i][j] --> d[4][i][j] 那么可以通过快速幂的方法来求解。
三、代码
#include <cstdio>
#include <cstring>
#include <iostream>
#include <map>
using namespace std;
const int N = 205, INF = 0x3f3f3f3f;
struct Matrix{
int d[N][N];
Matrix() {
memset(d, 0x3f, sizeof(d)); //代表走几条路到达最短路
}
};
int n, m, k, s, e, u, v, w;
Matrix one, ans; //one代表经过一条边时候的最短路径 这时候不用初始化d[i][i] = 0
//因为一条边的时候不能够到达自己本身 而ans是0条边的时候的最短路 这时候d[i][i] = 0,经过0条边到达自己
map<int, int> id;
Matrix mul(Matrix &a, Matrix &b) {
Matrix c;
for (int k = 1; k <= n; k++) {
for (int i = 1; i <= n; i++) { if (a.d[i][k] != INF) //减少不必要的循环
for (int j = 1; j <= n; j++) {
c.d[i][j] = min(c.d[i][j], a.d[i][k] + b.d[k][j]);
}
}
}
return c;
}
void qmul() {
for (int i = 1; i <= n; i++) ans.d[i][i] = 0;//这是0条边的最短路径
//ans代表经过0条边的最短路径 one是一条边 2者相乘就是 1条边的最短路径
//若求8条边的 只需要4条边的 * 4条边的即可
while (k) {
if (k & 1) {
ans = mul(ans, one);
}
one = mul(one, one);
k >>= 1;
}
}
int main() {
scanf("%d%d%d%d", &k, &m, &s, &e);
if (!id[s]) id[s] = ++n; s = id[s]; //分配标号离散化
if (!id[e]) id[e] = ++n; e = id[e]; //分配标号离散化
for (int i = 1; i <= m; i++) {
scanf("%d%d%d", &w, &u, &v);
if (!id[u]) id[u] = ++n; u = id[u];
if (!id[v]) id[v] = ++n; v = id[v];
one.d[u][v] = one.d[v][u] = min(one.d[u][v], w);
}
qmul();
printf("%d\n", ans.d[s][e]);
return 0;
}