题意:每天,农夫John需要经过一些道路去检查牛棚N里面的牛. 农场上有M(1<=M<=50,000)条双向泥土道路,编号为1..M. 道路i连接牛棚P1_i和P2_i (1 <= P1_i <= N; 1 <= P2_i<= N). John需要T_i (1 <= T_i <= 1,000,000)时间单位用道路i从P1_i走到P2_i或者从P2_i 走到P1_i 他想更新一些路经来减少每天花在路上的时间.具体地说,他想更新K (1 <= K <= 20)条路经,将它们所须时间减为0.帮助FJ选择哪些路经需要更新使得从1到N的时间尽量少.
思路:分层最短路。拆点最短路,将每个点拆成k个点来看待。
#include <bits/stdc++.h>
#define fi first
#define se second
using namespace std;
typedef long long LL;
typedef pair<LL,int> pii;
typedef pair<pii,int> piii;
const int maxn = 10005;
const int maxk = 25;
const int maxm = 100005;
int he[maxn],ver[maxm],ne[maxm],tot,cost[maxm];
void add( int x,int y,int w ){
ver[++tot] = y;
ne[tot] = he[x];
he[x] = tot;
cost[tot] = w;
}
int vis[maxn][maxk];
LL dis[maxn][maxk],K;
priority_queue< piii,vector<piii>,greater<piii> > Q;
void dijkstra(int s){
memset( dis,0x3f,sizeof(dis) );
dis[s][0] = 0;
Q.push( piii( pii(0,0),s ) );
while(Q.size()){
int x = Q.top().se;
int k = Q.top().fi.se;
Q.pop();
if( vis[x][k] ) continue;
vis[x][k] = 1;
for( int cure=he[x];cure;cure = ne[cure] ){
int y = ver[cure];
if( vis[y][k] ) continue;
if( dis[y][k] > dis[x][k] + cost[cure] ){
dis[y][k] = dis[x][k] + cost[cure];
Q.push( piii( pii( dis[y][k],k ),y ) );
}
}
for( int cure = he[x];cure;cure = ne[cure] ){
int y = ver[cure];
if( vis[y][k] || k == K ) continue;
if( dis[y][k+1] > dis[x][k] ){
dis[y][k+1] = dis[x][k];
Q.push( piii( pii( dis[y][k+1],k+1 ),y ) );
}
}
}
}
int main(){
int n,m,x,y,w;
scanf("%d%d%d",&n,&m,&K);
for( int i = 1;i <= m;i++ ){
scanf("%d%d%d",&x,&y,&w);
add(x,y,w);add(y,x,w);
}
dijkstra(1);
LL ans=0x3f3f3f3f3f3f3f3f;
for( int i = 0;i <= K;i++ ){
ans = min( ans,dis[n][i] );
}
printf("%d\n",ans);
return 0;
}