题目
约翰一共有N)个牧场.由M条布满尘埃的小径连接.小径可 以双向通行.每天早上约翰从牧场1出发到牧场N去给奶牛检查身体.通过每条小径都需要消耗一定的时间.约翰打算升级其中K条小径,使之成为高 速公路.在高速公路上的通行几乎是瞬间完成的,所以高速公路的通行时间为0.请帮助约翰决定对哪些小径进行升级,使他每天早上到牧场N花的时间最少.输出这个最少的时间.
分析
一个比较神的建图思路,建n+1层图,对于第i层表示已经将i条路改为了高速公路。同一层的连边权值不变,第j层到第j+1层如果它们本身有连边则边权为0,最后直接跑最短路即可。
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cctype>
#include<cmath>
#include<cstdlib>
#include<queue>
#include<ctime>
#include<vector>
#include<set>
#include<map>
#include<stack>
using namespace std;
vector<pair<long long,long long> >v[210010];
inline long long read(){
long long x=0,f=1;char s=getchar();
while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
while(s>='0'&&s<='9'){x=(x<<3)+(x<<1)+(s-'0');s=getchar();}
return x*f;
}
long long vis[250000],d[250000];
priority_queue<pair<long long,long long> >q;
int main()
{ long long n,m,i,j,k,t,x,y,z;
n=read(),m=read(),k=read();
for(i=1;i<=m;i++){
x=read(),y=read(),z=read();
for(j=0;j<=k;j++){
v[n*j+x].push_back(make_pair(n*j+y,z));
v[n*j+y].push_back(make_pair(n*j+x,z));
if(j){
v[n*(j-1)+x].push_back(make_pair(n*j+y,0));
v[n*(j-1)+y].push_back(make_pair(n*j+x,0));
}
}
}
memset(d,0x3f,sizeof(d));
q.push(make_pair(0,1));
d[1]=0;
while(!q.empty()){
x=q.top().second;
q.pop();
if(vis[x])continue;
for(i=0;i<v[x].size();i++)
if(d[x]+v[x][i].second<d[v[x][i].first]){
d[v[x][i].first]=d[x]+v[x][i].second;
q.push(make_pair(-d[v[x][i].first],v[x][i].first));
}
}
printf("%lld
",d[(k+1)*n]);
return 0;
}