EZOJ #375高速公路
分析
我们可以先跑一遍全价的最短路
之后我们枚举这个第k大的价格w[i]
将其它边减这个边的权值和0取max
在跑出最短路之后加上减去的费用,即w[i]*k
我们发现如果价值大于w[i]的边小于k个
那么由于小于w[i]的边经过之前操作后权值会比原先大所以一定不有
所以我们不难得出一定是这个点正好是第k大时才是最优的
最终所有答案取min即可
代码
#include<bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define mp make_pair
#define pb push_back
#define int long long
const int inf = 1e15+7;
int n,m,k,s,t,d[3010],vis[3010],wh,f[3010];
priority_queue<pair<int,int> >q;
vector<pair<int,int> >v[3010];
inline int dij(){
int i,j,k;
memset(vis,0,sizeof(vis));
for(i=1;i<=n;i++)d[i]=inf;
d[s]=0;
q.push(mp(0,s));
while(!q.empty()){
int x=q.top().se;
q.pop();
if(vis[x])continue;
vis[x]=1;
for(i=0;i<v[x].size();i++){
int y=v[x][i].fi,z=max(0ll,v[x][i].se-wh);
if(d[y]>d[x]+z){
d[y]=d[x]+z;
q.push(mp(-d[y],y));
}
}
}
return d[t];
}
signed main(){
int i,j;
scanf("%lld%lld%lld%lld%lld",&n,&m,&k,&s,&t);
for(i=1;i<=m;i++){
int x,y,z;
scanf("%lld%lld%lld",&x,&y,&z);
v[x].pb(mp(y,z));
f[i]=z;
}
int ans=dij();
for(i=1;i<=m;i++){
wh=f[i];
ans=min(ans,dij()+k*wh);
}
cout<<ans;
return 0;
}