给你n个点,m个边,s开始点,t结束点,有k次机会可以把m任意边权值变成0,问最短路是多少。
对于一般的求最短路,我们用一个一维dis[]就可以表示出源点到各个点直接的最短关系,由于这里考虑到可以有k次机会能能把权值变成0,所以我们要对每条边进行考虑,变0还是不变0,并且要考虑k次,因此我们用dis[i][j]来表示,i表示是用了i次机会把权值变成0,j是我们要求的点,于是我们就相当于把n个点分成了k层n点,考虑每个点的情况。
这里dijkstra算法在队列循环判断的时候,需要找到我已经求出最优的dis[i][j],把较小但是不对的出队,然后在每次比较边的时候都要分两种考虑,带上这条边,或者用一次机会不带这条边的权值,综合考虑取最优。
#include<iostream>
#include<cstdio>
#include<queue>
#include<algorithm>
using namespace std;
const int maxn = 3005;
int inf = 1e9;
int head[maxn],dis[maxn][maxn];
int tot=0,n,m,s,t,k;
struct EG{
int next,to,w;
}e[maxn*2];
struct node{
int a,id,dis;
node(){}
node(int a,int id,int dis) : a(a),id(id),dis(dis){}
bool operator < (const node& b)const{
return dis > b.dis;
}
};
void add(int a,int b,int w){
e[++tot].next = head[a];
e[tot].to = b;
e[tot].w = w;
head[a] = tot;
}
void Dj(int a,int s){
for(int i = 0; i <= k; i++)
for(int j = 1; j <= n; j++)
dis[i][j] = inf;
priority_queue<node> q;
q.push(node(0,s,0));
dis[a][s] = 0;
while(q.size()){
node d = q.top();q.pop();
if(d.dis!=dis[d.a][d.id]) continue;//这里是要找到当前求出的最优解
if(q.size()==0 && d.dis!=dis[d.a][d.id]) break;
for(int i = head[d.id];i;i = e[i].next){
int v = e[i].to;
if(dis[d.a][v] > dis[d.a][d.id]+e[i].w){
dis[d.a][v] = dis[d.a][d.id]+e[i].w;
q.push(node(d.a,v,dis[d.a][v]));
}
if(d.a < k && dis[d.a+1][v] > dis[d.a][d.id]){
dis[d.a+1][v] = dis[d.a][d.id];
q.push(node(d.a+1,v,dis[d.a+1][v]));
}
}
}
}
void read(){
scanf("%d%d%d%d%d",&n,&m,&s,&t,&k);
for(int i = 1; i <= m;i ++){
int a,b,w; scanf("%d%d%d",&a,&b,&w);
add(a,b,w);
add(b,a,w);
}
}
int main(){
// init();
read();
Dj(0,s);
int ans = inf;
for(int i=0;i<=k;i++)
ans = min(ans,dis[i][t]);
printf("%d\n",ans);
return 0;
}

本文介绍了一种基于Dijkstra算法的优化方案,用于解决特定条件下寻找最短路径的问题。在n个点和m条边的图中,从起点s到终点t,允许k次将任意边的权值置为0,以此求得最短路径。通过将n个点扩展至k层n点,结合Dijkstra算法,实现了对每条边是否使用机会的考量,最终找出全局最优解。
656

被折叠的 条评论
为什么被折叠?



