题意:有A个村子B个城堡,1~A为村子,A+1 ~ A + B为城堡,有一双可以使用K次的魔法鞋,可以瞬移,但一次不能超过L米,且不能在路中停下,不能闯过城堡,问1 -> A + B的最短时间。
思路1:dijkstra,设d[u][j][k] : 到达u村(城)时,第j次使用的鞋子距离还剩下k时候的最短路,则有:
1、不使用鞋子:d[v][j][k] = min{ d[v][j][k]), d[u][j][k] + w(u,v) }
2、使用鞋子分v是村子或者城堡,还有k是否大于w(u,v)
这种较麻烦
#include<cstdio>
#include<cstring>
#include<queue>
#include<vector>
#include<algorithm>
const int maxn = 1e2 + 10;
const int INF = 1e9 + 10;
using namespace std;
struct P {
int to, th, res, cost;
P() {}
P(int t, int tt, int r, int cost) :
to(t), th(tt), res(r), cost(cost) {}
bool operator < (P a) const {
return cost > a.cost;
}
};
int d[maxn][15][550];
int T, A, B, K, L, M;
vector<P> G[maxn];
int dijkstra() {
for(int i = 0; i < maxn; i++) {
for(int j = 0; j < 15; j++)
for(int k = 0; k < 550; k++)
d[i][j][k] = INF;
}
d[1][K + 1][0] = 0;
priority_queue<P> q;
q.push(P(1, K + 1, 0, 0));
while(!q.empty()) {
P p = q.top(); q.pop();
if(p.to == A + B) return p.cost;
int u = p.to, j = p.th, k = p.res, co = p.cost;
if(d[u][j][k] < co) continue;
for(int i = 0; i < G[u].size(); i++) {
P st = G[u][i];
int v = st.to, c = st.cost;
///u -> v不使用鞋子
if(co + c < d[v][j][0]) {
d[v][j][0] = co + c;
q.push(P(v, j, 0, d[v][j][0]));
}
///u -> v使用鞋子
///v是城堡
if(v > A && k >= c && co < d[v][j][0]) {
d[v][j][0] = co;
q.push(P(v, j, 0, d[v][j][0]));
}
if(v > A && k < c && j > 1 && co < d[v][j][0] && L >= c) {
d[v][j - 1][0] = co;
q.push(P(v, j - 1, 0, d[v][j - 1][0]));
}
///v是村子
if(v <= A && k >= c && co < d[v][j][k - c]) {
d[v][j][k - c] = co;
q.push(P(v, j, k - c, co));
}
if(v <= A && k < c && j > 1 && L >= c && co < d[v][j - 1][L - c]) {
d[v][j - 1][L - c] = co;
q.push(P(v, j - 1, L - c, co));
}
}
}
}
int main() {
scanf("%d", &T);
while(T--) {
scanf("%d%d%d%d%d", &A, &B, &M, &L, &K);
for(int i = 0; i < maxn; i++) G[i].clear();
while(M--) {
int f, t, c;
scanf("%d %d %d", &f, &t, &c);
G[f].push_back(P(t, 0, 0, c));
G[t].push_back(P(f, 0, 0, c));
}
int ans = dijkstra();
printf("%d\n", ans);
}
return 0;
}
思路2:设d[i][j] : 到达第i个村子(城堡)还剩j次魔法鞋的最短路,则先求一次floyd求出所有用魔法鞋不受阻碍可到达的下一个地点,有:
1、不使用鞋子 d[u][j] = min{d[i][j] + w(u, i)}
2、使用鞋子(j > 0) d[u][j - 1] = min { d[i][j] }
#include<cstdio>
#include<cstring>
#include<queue>
#include<vector>
#include<algorithm>
const int maxn = 1e2 + 10;
const int INF = 1e9 + 10;
using namespace std;
int fy[maxn][maxn];
int d[maxn][15];
int vis[maxn * 20];
int A, B, M, L, K, T;
vector<int> G[maxn];
void floyd() {
for(int k = 1; k <= A; k++) {
for(int i = 1; i <= A + B; i++) {
for(int j = 1; j <= A + B; j++) {
fy[i][j] = min(fy[i][j], fy[i][k] + fy[k][j]);
}
}
}
}
void spfa() {
for(int i = 0; i <= K; i++) d[1][i] = 0;
memset(vis, 0, sizeof(vis));
queue<int> q; q.push(15 + K);
vis[15 + K] = 1;
while(!q.empty()) {
int sta = q.front(); q.pop();
vis[sta] = 0;
int x = sta / 15, y = sta % 15;
for(int u = 1; u <= A + B; u++) {
if(x == u) continue;
if(d[x][y] + fy[x][u] < d[u][y]) {
d[u][y] = d[x][y] + fy[x][u];
int st1 = u * 15 + y;
if(!vis[st1]) { q.push(st1); vis[st1] = 1; }
}
if(fy[x][u] > L || !y || d[u][y - 1] <= d[x][y]) continue;
d[u][y - 1] = d[x][y];
int sy = u * 15 + y - 1;
if(!vis[sy]) { vis[sy] = 1; q.push(sy); }
}
}
}
int main() {
scanf("%d", &T);
while(T--) {
scanf("%d%d%d%d%d", &A, &B, &M, &L, &K);
for(int i = 0; i < maxn; i++) {
for(int j = 0; j < maxn; j++) {
fy[i][j] = INF;
if(j < 15) d[i][j] = INF;
}
fy[i][i] = 0;
}
while(M--) {
int f, t, c;
scanf("%d %d %d", &f, &t, &c);
fy[f][t] = fy[t][f] = c;
}
floyd();
spfa();
int ans = INF;
for(int i = 0; i < 15; i++) ans = min(ans, d[A + B][i]);
printf("%d\n", ans);
}
return 0;
}