题目
题目大意:有n个村庄和m个城堡,编号从1到n+m,给出一个有权图,没有自环和重边。马里奥走一个单位距离需要一个单位时间。起点为城堡n+m,终点为乡村1。马里奥可以瞬移K次,每次瞬移不超过距离L,且起点和终点必须为村庄或城堡、到达一个城堡时必须结束当前瞬移。求到达村庄1的最小花费时间。
详见uva10269
解题思路
D P [ i ] [ j ] [ k ] DP[i][j][k] DP[i][j][k]表示到达城市 i i i,还剩 j j j次瞬移机会,上次瞬移机会还剩下 k k k单位距离可以使用。分类讨论,状态过多,具体看代码注释。
结合最短路的思想,只有一个点被松弛成功了,这个点才压入队列。
代码
#include <bits/stdc++.h>
using namespace std;
int dp[110][12][510]; //dp[i][j][k]表示到了第i号位置 还剩j次瞬移机会 上次的瞬移还剩下k单位能使用 的最小花费
vector<pair<int, int>> mp[110];
int A, B, M, L, K;
bool vis[110];
void bfs(int s)
{
dp[s][K][0] = 0;
queue<int> q;
q.push(s);
while (q.size())
{
int pos = q.front();
q.pop();
vis[pos] = 0;
for (auto it : mp[pos])
{
int v = it.first;
int w = it.second;
for (int j = 0; j <= K; j++) //剩余j次瞬移机会
{
for (int k = 0; k <= L; k++) //上次的瞬移还剩下k单位
{
if (k >= w) //这段距离小于上次剩下的瞬移k
{
if (pos <= A) //上一个不是城堡 继续使用上次瞬移
{
if (dp[v][j][k - w] > dp[pos][j][k])
{
dp[v][j][k - w] = dp[pos][j][k];
if (!vis[v])
q.push(v), vis[v] = 1;
}
}
else //上一个是城堡,考虑当前要不要使用瞬移
{
if (dp[v][j][L - w] > dp[pos][j + 1][k]) //使用瞬移
{
dp[v][j][L - w] = dp[pos][j + 1][k];
if (!vis[v])
q.push(v), vis[v] = 1;
}
if (dp[v][j][0] > dp[pos][j][k] + w) //不使用瞬移
{
dp[v][j][0] = dp[pos][j][k] + w;
if (!vis[v])
q.push(v), vis[v] = 1;
}
}
}
else
{
if (w > L) //只能老老实实走
{
if (dp[v][j][0] > dp[pos][j][k] + w)
{
dp[v][j][0] = dp[pos][j][k] + w;
if (!vis[v])
q.push(v), vis[v] = 1;
}
}
else
{
if (dp[v][j][0] > dp[pos][j][k] + w) //老老实实走
{
dp[v][j][0] = dp[pos][j][k] + w;
if (!vis[v])
q.push(v), vis[v] = 1;
}
if (dp[v][j][L - w] > dp[pos][j + 1][k]) //再使用一次瞬移
{
dp[v][j][L - w] = dp[pos][j + 1][k];
if (!vis[v])
q.push(v), vis[v] = 1;
}
}
}
}
}
}
}
int ans = 0x3f3f3f3f;
for (int j = 0; j <= K; j++) //剩余j次瞬移机会
for (int k = 0; k <= L; k++) //剩下k单位瞬移
ans = min(ans, dp[1][j][k]);
cout << ans << endl;
}
void solve()
{
cin >> A >> B >> M >> L >> K;
for (int i = 1; i <= A + B; i++)
mp[i].clear();
for (int i = 1; i <= M; i++)
{
int u, v, w;
cin >> u >> v >> w;
mp[u].emplace_back(make_pair(v, w));
mp[v].emplace_back(make_pair(u, w));
}
memset(dp, 0x3f3f3f3f, sizeof dp);
memset(vis, 0, sizeof vis);
bfs(A + B);
}
int main()
{
int t;
cin >> t;
while (t--)
solve();
return 0;
}