1.题意:给出n个 城市,m条路的有向图,每条路有路费,但是可以选择k条路免费通过,问从城市1到达城市n的最低花费。
2.分析: 分层图最短路问题,用dist [i] [j] 表示到达 i 城市,免费了j条路时的最低花费,那么从当前点到达下一个点时就有两种选择:
(1)两点间的这条路不免费,dist[to][j] = dist[i][j] + val;
(2)若j+1<=k 则这条路可以选择免费 : dist[to][j+1] = dist [i] [j] + 0;
最后判断dist[n][1~k]的最小(因为dist[n][k]不一定是最小的)
3.代码:
#include <iostream>
#include<bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
typedef long long LL;
const int maxn = 100000 + 7;
struct Edge{
int to,next;
LL val;
}edge[maxn*2];
LL dist[maxn][11],head[maxn];
bool vis[maxn][11];
int n,m,k,tot;
void addEdge(int a,int b,LL c){
edge[tot].to = b;edge[tot].next = head[a];edge[tot].val = c;head[a] = tot++;
}
struct Node{
int p,x;//当前点,当前免费次数,当前总花费
LL v;
bool operator <(const Node &another)const{
return v>another.v;
}
Node(int a,int b,LL c):p(a),x(b),v(c) {}
};
void Dijkstra(int s){
memset(dist,INF,sizeof(dist));
for(int i = 0;i<=k;i++)dist[s][i] = 0;
priority_queue<Node> que;
que.push(Node(s,0,0));
while(!que.empty()){
Node node = que.top();
que.pop();
if(vis[node.p][node.x])continue;
vis[node.p][node.x] = 1;//标记
int u = node.p;
int num = node.x;
for(int i = head[u];~i;i = edge[i].next){
if(!vis[edge[i].to][num]&&edge[i].val + dist[u][num]<dist[edge[i].to][num]){
dist[edge[i].to][num] = edge[i].val + dist[u][num];//这条路不免费
que.push(Node(edge[i].to,num,dist[edge[i].to][num]));
}
if(!vis[edge[i].to][num+1]&&num<k&&dist[edge[i].to][num+1]>dist[u][num]){
dist[edge[i].to][num+1]=dist[u][num];//这条路免费
que.push(Node(edge[i].to,num+1,dist[edge[i].to][num+1]));
}
}
}
}
int main()
{
int T;
scanf("%d",&T);
while(T--){
tot = 0;
memset(vis,0,sizeof(vis));
memset(head,-1,sizeof(head));
scanf("%d%d%d",&n,&m,&k);
for(int i = 0;i<m;i++){
int a,b;
LL v;
scanf("%d%d%lld",&a,&b,&v);
addEdge(a,b,v);//有向图链式前向星
}
Dijkstra(1);
LL minn = INF;
for(int i = 0;i<=k;i++){//取最小
minn = min(minn,dist[n][i]);
}
printf("%lld\n",minn);
}
return 0;
}