D78 分层图最短路 Dijkstra 算法 CF1915G Bicycles

D78 分层图最短路 Dijkstra 算法 CF1915G Bicycles_哔哩哔哩_bilibili

 

CF1915G Bicycles - 洛谷

思路

问题是求最短路,花费由点权和边权乘积决定,到一个点时,点权(即速度)可换可不换

到达每一个点的决策有两种可能性:

  1. 不换速度,以原速度继续前进
  2. 换当前点上的速度,继续前进

考虑分层图最短路,按速度($\le1000$)分层,每到达一个点,根据是否换速度做两次松弛更新

d[i][j] 表示到达点 i 使用速度 j 的最小花费

        image

优化:根据贪心思想,到达一个点时,如果该点的速度更小,就只更新该速度的状态;如果原速度更小,就只更新原速度的状态

相关板子:

D75【模板】分层图最短路 Dijkstra 算法 P4568 [JLOI2011] 飞行路线 - 董晓 - 博客园

 

// 分层图最短路 Dijkstra 算法 O(mk*log(nk))
#include<bits/stdc++.h>
using namespace std;

const int N=1005;
int h[N],idx,to[N<<1],ne[N<<1],w[N<<1];
void add(int x,int y,int z){
  to[++idx]=y,w[idx]=z,ne[idx]=h[x],h[x]=idx;
}
struct node{
  long long d; int v,s; //花费,点,速度
  bool operator<(const node &b)const&{
    return d>b.d;
  }
};
int n,m,a[N];
long long d[N][N]; //d[i][j]表示到点i使用速度j的最小花费

void dijkstra(){
  memset(d,0x3f,sizeof d); d[1][a[1]]=0;
  priority_queue<node> q;
  q.push({0,1,a[1]});
  while(!q.empty()){
    auto [dd,u,s]=q.top();q.pop();
    if(dd!=d[u][s])continue;
    for(int i=h[u];i;i=ne[i]){
      int v=to[i];
      long long ww=1ll*s*w[i]; //花费
      if(d[v][s]>d[u][s]+ww){  //不换速度
        d[v][s]=d[u][s]+ww;
        q.push({d[v][s],v,s});
      }
      if(d[v][a[v]]>d[u][s]+ww){ //换速度
        d[v][a[v]]=d[u][s]+ww;
        q.push({d[v][a[v]],v,a[v]});
      }
    }
  }
}
int main(){
  int t; cin>>t;
  while(t--){
    cin>>n>>m;
    idx=0; memset(h,0,sizeof h);
    for(int i=1,u,v,w;i<=m;i++){
      cin>>u>>v>>w;
      add(u,v,w);add(v,u,w);
    }
    for(int i=1;i<=n;i++)cin>>a[i]; //速度
    dijkstra();
    long long ans=1e18;
    for(int i=1;i<=n;i++)ans=min(ans,d[n][a[i]]);
    cout<<ans<<"\n";
  }
}

 

// 分层图最短路 Dijkstra 算法 O(mk*log(nk))
#include<bits/stdc++.h>
using namespace std;

const int N=1005;
int h[N],idx,to[N<<1],ne[N<<1],w[N<<1];
void add(int x,int y,int z){
  to[++idx]=y,w[idx]=z,ne[idx]=h[x],h[x]=idx;
}
struct node{
  long long d; int v,s; //花费,点,速度
  bool operator<(const node &b)const&{
    return d>b.d;
  }
};
int n,m,a[N];
long long d[N][N]; //d[i][j]表示到点i使用速度j的最小花费

void dijkstra(){
  memset(d,0x3f,sizeof d); d[1][a[1]]=0;
  priority_queue<node> q;
  q.push({0,1,a[1]});
  while(!q.empty()){
    auto [dd,u,s]=q.top();q.pop();
    if(dd!=d[u][s])continue;
    for(int i=h[u];i;i=ne[i]){
      int v=to[i];
      long long ww=1ll*s*w[i]; //花费
      int sp=min(s,a[v]);      //贪心最小速度
      if(d[v][sp]>d[u][s]+ww){
        d[v][sp]=d[u][s]+ww;
        q.push({d[v][sp],v,sp});
      }
    }
  }
}
int main(){
  int t; cin>>t;
  while(t--){
    cin>>n>>m;
    idx=0; memset(h,0,sizeof h);
    for(int i=1,u,v,w;i<=m;i++){
      cin>>u>>v>>w;
      add(u,v,w);add(v,u,w);
    }
    for(int i=1;i<=n;i++)cin>>a[i]; //速度
    dijkstra();
    long long ans=1e18;
    for(int i=1;i<=n;i++)ans=min(ans,d[n][a[i]]);
    cout<<ans<<"\n";
  }
}

 

posted @ 2026-02-19 19:42  董晓  阅读(161)  评论(0)    收藏  举报