题意:在图上,有k次机会可以直接通过一条边而不计算边权,问起点与终点之间的最短路径。
思路:类似于求最短路经,但由于可以有k次机会不计算边权,所以需要加上一维状态表示用了几次机会。
Code:
#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std;
const int AX = 1e4+66;
int s , t ;
int n , m , k ;
struct Node{
int v ;
int dis ;
int level ;
bool operator < ( const Node &x ) const{
return x.dis < dis ;
}
};
std::vector<Node> G[AX];
priority_queue<Node> q;
bool vis[AX][20];
int dis[AX][20];
void dji(){
while( !q.empty() ){
Node tmp = q.top();
q.pop();
int v = tmp.v;
int level = tmp.level;
if( vis[v][level] ) continue;
vis[v][level] = true ;
for( int i = 0 ; i < G[v].size() ; i++ ){
int to = G[v][i].v ;
int w = G[v][i].dis;
if( w + dis[v][level] < dis[to][level] ){
dis[to][level] = w + dis[v][level];
q.push((Node){to,dis[to][level],level});
}
if( level < k && dis[v][level] < dis[to][level+1] ){
dis[to][level+1] = dis[v][level];
q.push((Node){to,dis[to][level+1],level+1});
}
}
}
}
int main(){
int x , y , w ;
scanf("%d%d%d",&n,&m,&k);
scanf("%d%d",&s,&t);
for( int i = 0 ; i <= n ; i++ ) G[i].clear();
for( int i = 0 ; i < m ; i++ ){
scanf("%d%d%d",&x,&y,&w);
G[x].push_back((Node){y,w});
G[y].push_back((Node){x,w});
}
memset( vis , false , sizeof(vis) ) ;
for( int i = 0 ; i < n ; i++ ){
for( int j = 0 ; j <= k ; j++ ){
dis[i][j] = INF;
}
}
dis[s][0] = 0 ;
q.push((Node){s,0,0});
dji();
int res = dis[t][0];
for( int i = 1 ; i <= k ; i++ ){
res = min( res , dis[t][i] );
}
printf("%d\n",res);
return 0 ;
}