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;
}
posted @ 2019-09-14 21:56  水题收割者  阅读(94)  评论(0编辑  收藏  举报