题目链接:J--Free
题意:给你n个点,m条边,让你从s走到t,最多使得k条边的边权变为0的条件下,问s到t的最短距离是多少
当时没想到需要dp的思想,只是跑了一遍最短路,记录一下路径,把前k大的边减去就过了,数据水了
dp[i][j] 表示到i节点时 把j条边的权值变为0的最短距离
dp的思想就是对于k条边,可选,可不选,如果选, dp[to][k] = dp[fa][k] + w,不选 dp[to][k+1] = dp[fa][k]
#include <iostream>
#include <cstdio>
#include <queue>
#define ll long long
#define INF 0x3f3f3f3f
using namespace std;
const int maxn = 1e6+5;
const int N = 1005;
struct node {
int to, nex, w;
}e[maxn];
int cnt, n, m, s, t, k;
int head[N], dp[N][N], vis[N][N];
void add(int u, int v, int w) {
e[cnt].to = v;
e[cnt].w = w;
e[cnt].nex = head[u];
head[u] = cnt++;
}
struct Node {
int x, k, val;
bool operator < (const Node &a)const {
return val > a.val;
}
};
void Dj(){
for(int i=0;i<=n;i++)
for(int j=0;j<=k;j++)
dp[i][j]=INF, vis[i][j]=0;
priority_queue<Node> q;
q.push(Node{s, 0, 0});
dp[s][0]=0;
while(!q.empty()) {
Node now = q.top(); q.pop();
int x = now.x;
if(vis[x][now.k])continue;
vis[x][now.k] = 1;
for(int i = head[x]; i != -1; i = e[i].nex) {
int to = e[i].to;
int w = e[i].w;
if(dp[to][now.k] > dp[x][now.k] + w) {
dp[to][now.k] = dp[x][now.k] + w;
q.push(Node{to, now.k, dp[to][now.k]});
}
if(now.k < k && dp[to][now.k + 1] > dp[x][now.k]) {
dp[to][now.k + 1] = dp[x][now.k];
q.push(Node{to, now.k + 1, dp[to][now.k]});
}
}
}
int ans = INF;
for(int i=0;i<=k;i++) {
ans = min(ans, dp[t][i]);
}
printf("%d\n",ans);
}
int main()
{
scanf("%d %d %d %d %d", &n, &m, &s, &t, &k);
for(int i = 0; i <= n; ++i) head[i] = -1;
for(int i = 0; i < m; ++i) {
int x, y, w;
scanf("%d %d %d", &x, &y, &w);
add(x, y, w);
add(y, x, w);
}
Dj();
return 0;
}