p2939 改造路

传送门

题目

约翰一共有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;
}
原文地址:https://www.cnblogs.com/yzxverygood/p/9200633.html