D83 分层图最短路 Dijkstra 算法 HDU 6805 Deliver the Cake

D83 分层图最短路 Dijkstra 算法 HDU 6805 Deliver the Cake_哔哩哔哩_bilibili

 

Problem - HDU 6805 Deliver the Cake

给 n 个点 m 条无向边,每条边输入信息为:u,v,w 表示从 u 点到 v 点的边权为 w

每一个点会有一个属性 L、R 或 M,如果 u 和  v 一个为 L,另一个为 R,那么 u 和 v 之间的边权要增加 x,其他情况不变

输出从 s 点到 t 点的最短距离

思路

点的属性表达通常是拆点,每个点拆成两个点(v和v+n),分为上、下两层,

上层表示属性 L,下层表示属性 R,属性 M 表示两种属性都具备

连边时,讨论属性的排列,分为九种情况,合并两种后为七种

属性相同,层内连边,边权不变;属性不同,层间连边,边权增加 x

注意跑最短路时,把起点的两个拆点都入队,还有,答案在终点的两个拆点中找

image

相关板子:

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

 

// 分层图最短路 Dijkstra 算法 O(MlogN)
#include<bits/stdc++.h>
#define int long long
#define pii pair<int,int>
using namespace std;

const int N=4e5+5,M=2e6;
int h[N],idx,to[M],ne[M]; int ww[M];
void add(int u,int v,int w){
  to[++idx]=v;ww[idx]=w;ne[idx]=h[u];h[u]=idx;
  to[++idx]=u;ww[idx]=w;ne[idx]=h[v];h[v]=idx;
}
int n,m,s,t; int x; char ch[N];
int d[N];
bool vis[N];

void dijkstra(){
  memset(d,0x3f,sizeof d); d[s]=0; d[s+n]=0;
  memset(vis,0,sizeof vis);
  priority_queue<pii,vector<pii>,greater<pii>> q;
  q.push({0,s}); q.push({0,s+n});
  
  while(!q.empty()){
    auto u=q.top().second; q.pop();
    if(vis[u])continue; vis[u]=1;
    for(int i=h[u];i;i=ne[i]){
      int v=to[i]; int w=ww[i];
      if(d[v]>d[u]+w){
        d[v]=d[u]+w;
        q.push({d[v],v});
      }
    }
  }
}
signed main(){
  int T; cin>>T;
  while(T--){
    scanf("%lld%lld%lld%lld%lld",&n,&m,&s,&t,&x); scanf("%s",ch+1);
    idx=0; memset(h,0,sizeof h);
    for(int i=0,u,v,w; i<m; i++){
      scanf("%lld%lld%lld",&u,&v,&w);
      if((ch[u]=='L'&&ch[v]=='L')||(ch[u]=='R'&&ch[v]=='R'))add(u,v,w);
      else if((ch[u]=='L'&&ch[v]=='R')||(ch[u]=='R'&&ch[v]=='L'))add(u,v,x+w);
      else if(ch[u]=='L'&&ch[v]=='M')add(u,v,w),add(u,v+n,x+w); //v拆成v和v+n,LL,LR
      else if(ch[u]=='R'&&ch[v]=='M')add(u,v,x+w),add(u,v+n,w); //RL,RR
      else if(ch[u]=='M'&&ch[v]=='L')add(u,v,w),add(u+n,v,x+w); //LL,RL
      else if(ch[u]=='M'&&ch[v]=='R')add(u,v,x+w),add(u+n,v,w); //LR,RR
      else if(ch[u]=='M'&&ch[v]=='M')add(u,v,w),add(u,v+n,x+w),
                                     add(u+n,v,x+w),add(u+n,v+n,w); //LL,LR,RL,RR
    }

    dijkstra();
    printf("%lld\n",min(d[t],d[t+n]));
  }
}

 

// 分层图最短路 Dijkstra 算法 O(MlogN)
#include<bits/stdc++.h>
#define int long long
#define pii pair<int,int>
#define ipi pair<int,pii>
using namespace std;

const int N=1e5+5;
vector<pii> e[N];
int n,m,s,t,x; char ch[N];
int d[N][2];  //0:L,1:R
bool vis[N][2];

int get(char c){
  if(c=='L') return 0;
  if(c=='R') return 1;
  return 2;
}
void dijkstra(int s){
  memset(d,0x3f,sizeof d);
  memset(vis,0,sizeof vis);
  priority_queue<ipi,vector<ipi>,greater<ipi> >q;
  if(ch[s]=='L') q.push({d[s][0]=0,{s,0}});
  else if(ch[s]=='R') q.push({d[s][1]=0,{s,1}});
  else q.push({d[s][0]=0,{s,0}}),q.push({d[s][1]=0,{s,1}});

  while(!q.empty()){
    auto [u,p]=q.top().second; q.pop();
    if(vis[u][p])continue; vis[u][p]=1;
    for(auto [v,w]:e[u]){
      int k=get(ch[v]);
      if(p!=k && k!=2){ //LR,RL
        if(d[v][k]>d[u][p]+w+x){ 
          d[v][k]=d[u][p]+w+x;  //u,v不同时,加费走边
          q.push({d[v][k],{v,k}});
        }
      }
      else{ //LL,RR,LM,RM
        if(d[v][p]>d[u][p]+w){ 
          d[v][p]=d[u][p]+w;  //u,v相同或v不定时,定v走边
          q.push({d[v][p],{v,p}});
        }        
      }
    }
  }
}
signed main(){
  int T; cin>>T;
  while(T--){
    scanf("%lld%lld%lld%lld%lld",&n,&m,&s,&t,&x); scanf("%s",ch+1);
    for(int i=1; i<=n; i++) e[i].clear();
    for(int i=1,u,v,w; i<=m; i++){
      scanf("%lld%lld%lld",&u,&v,&w);
      e[u].push_back({v,w});
      e[v].push_back({u,w});
    }
    
    dijkstra(s);
    printf("%lld\n",min(d[t][0],d[t][1]));
  }
}
 

 

posted @ 2026-02-24 08:58  董晓  阅读(101)  评论(0)    收藏  举报