我是靠谱客的博主 壮观面包,最近开发中收集的这篇文章主要介绍L3-007 天梯地图(Dijkstra(两边权+一边权一点权)),觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

  • 题目链接:L3-007 天梯地图
  • 考查知识:Dijkstra(两边权+一边权一点权)
  • 题意描述:
    • 给定n个地点和m条道路,按以下要求任意给定两点间距离。
    • 如果最快到达路线不唯一,则输出几条最快路线中最短的那条,题目保证这条路线是唯一的。
    • 而如果最短距离的路线不唯一,则输出途径节点数最少的那条,题目保证这条路线是唯一的。
  • 思路简析:根据题意两遍dijkstra,第一遍是第一标尺时间(边权),第二标尺距离(边权);第二遍第一标尺距离(边权),第二标尺点数(点权);然后比较两个路径序列即可
    • 需要注意的是第一遍dijkstra的第二标尺的选择是 e [ u ] [ j ] < e [ p r e [ j ] ] [ j ] e[u][j]<e[pre[j]][j] e[u][j]<e[pre[j]][j]而不是 d [ u ] + e [ u ] [ j ] < d [ j ] d[u]+e[u][j]<d[j] d[u]+e[u][j]<d[j]
  • 具体代码
    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N=5e2+100,inf=0x3fffffff;
    int vis[N],d[N],e[N][N],pre[N],p[N],t[N][N],pre2[N],num[N],pre3[N];
    void dijkstra(int n,int s){
    vis[s]=1;
    for(int i=0;i<n-1;i++){
    int u=-1,mi=inf;//找与起点联通的点中未访问的且边权最小的点[1,n] 
    for(int j=0;j<n;j++){//编号[0,n) 
    if(!vis[j]&&p[j]<mi){
    u=j;
    mi=p[j];
    }
    }
    if(u==-1)break;
    else vis[u]=1;
    for(int j=0;j<n;j++){//找通过该中介点与起点联通的点中未访问的且可更新对应边权的点,更新其对应的最小边权[1,n] 
    if(!vis[j]&&p[u]+t[u][j]<p[j]){
    p[j]=p[u]+t[u][j];
    pre[j]=u;
    }else if(!vis[j]&&p[u]+t[u][j]==p[j]){
    if(e[u][j]<e[pre[j]][j]){//注意不是d[u]+e[u][j]<d[j]
    p[j]=p[u]+t[u][j];
    pre[j]=u;
    }
    }
    }
    }
    }
    void dijkstra2(int n,int s){
    vis[s]=1;
    for(int i=0;i<n-1;i++){
    int u=-1,mi=inf;//找与起点联通的点中未访问的且边权最小的点[1,n] 
    for(int j=0;j<n;j++){//编号[0,n) 
    if(!vis[j]&&d[j]<mi){
    u=j;
    mi=d[j];
    }
    }
    if(u==-1)break;
    else vis[u]=1;
    for(int j=0;j<n;j++){//找通过该中介点与起点联通的点中未访问的且可更新对应边权的点,更新其对应的最小边权[1,n] 
    if(!vis[j]&&d[u]+e[u][j]<d[j]){
    d[j]=d[u]+e[u][j];
    pre2[j]=u;
    num[j]=num[u]+1;
    }else if(!vis[j]&&d[u]+e[u][j]==d[j]){
    if(num[u]+1<num[j]){
    num[j]=num[u]+1;
    pre2[j]=u;
    }
    }
    }
    }
    }
    int judge(int a[],int n,int b[],int m){
    if(n!=m)return 0;
    else{
    for(int i=0;i<n;i++){
    if(a[i]!=b[i])return 0;
    }
    return 1;
    }
    }
    int main(){
    ios::sync_with_stdio;
    cin.tie(0),cout.tie(0);
    int n,m,s,v;
    cin>>n>>m;
    for(int i=0;i<n;i++){//无向图初始化 
    for(int j=0;j<n;j++){
    if(i!=j){
    e[i][j]=e[j][i]=inf;
    t[i][j]=t[j][i]=inf;
    }
    }
    }
    int x,y,z,w,q;
    while(m--){//读入边 
    cin>>x>>y>>z>>w>>q;
    e[x][y]=w,t[x][y]=q;
    if(!z)e[y][x]=w,t[y][x]=q;
    }
    cin>>s>>v;//起点,终点 
    for(int i=0;i<n;i++){
    d[i]=e[s][i],p[i]=t[s][i];
    }
    memset(pre,-1,sizeof(pre));
    dijkstra(n,s);
    memset(vis,0,sizeof(vis));
    memset(pre2,-1,sizeof(pre2));
    dijkstra2(n,s);
    int cn=0,cn2=0,road[N],road2[N],k=v,l=v;
    while(k!=-1){
    road[cn++]=k;
    k=pre[k];
    }
    while(l!=-1){
    road2[cn2++]=l;
    l=pre2[l];
    }
    int mit=p[v],mid=d[v];//最短时间 
    if(judge(road,cn,road2,cn2)){
    cout<<"Time = "<<mit<<"; Distance = "<<mid<<": "<<s;
    for(int i=cn-1;i>=0;i--){
    cout<<" => "<<road[i];
    }
    }else{
    cout<<"Time = "<<mit<<": "<<s;
    for(int i=cn-1;i>=0;i--){
    cout<<" => "<<road[i];
    }
    cout<<endl;
    cout<<"Distance = "<<mid<<": "<<s;
    for(int i=cn2-1;i>=0;i--){
    cout<<" => "<<road2[i];
    }
    }
    return 0;
    }
    
    • 用到了两次dijkstra,是因为据题意,两条路径的第一标尺不一样,所以无法根据传统的第一二三标尺依次去选择最佳路径
    • 但是也可以强行把两个dijkstra的代码合到一起,代码量略少一点 (;¬д¬),可以交换数组+标记变量实现
    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N=5e2+100,inf=0x3fffffff;
    int vis[N],d[N],e[N][N],pre[N],p[N],t[N][N],pre2[N],num[N],flag=1;
    void dijkstra(int n,int s){
    vis[s]=1;
    for(int i=0;i<n-1;i++){
    int u=-1,mi=inf;//找与起点联通的点中未访问的且距离最近的点[1,n] 
    for(int j=0;j<n;j++){//编号[0,n) 
    if(!vis[j]&&p[j]<mi){
    u=j;
    mi=p[j];
    }
    }
    if(u==-1)break;//如果没有与起点联通的点了,则算法结束 
    else vis[u]=1;//标记该点已访问
    for(int j=0;j<n;j++){//找通过该中介点与起点联通的点中未访问的且可更新对应边权的点,更新其对应的最小边权[1,n] 
    if(!vis[j]&&p[u]+t[u][j]<p[j]){
    p[j]=p[u]+t[u][j];
    num[j]=num[u]+1;
    if(flag)pre[j]=u;
    else pre2[j]=u;
    }else if(!vis[j]&&p[u]+t[u][j]==p[j]){
    if(flag&&e[u][j]<e[pre[j]][j]){
    p[j]=p[u]+t[u][j];
    pre[j]=u;//题目保证这条路线是唯一的,所以不用担心被下面的pre[j]=u影响 
    }
    if(!flag&&num[u]+1<num[j]){
    num[j]=num[u]+1;
    pre2[j]=u;
    }
    }
    }
    }
    }
    int judge(int a[],int n,int b[],int m){
    if(n!=m)return 0;
    else{
    for(int i=0;i<n;i++){
    if(a[i]!=b[i])return 0;
    }
    return 1;
    }
    }
    int main(){
    ios::sync_with_stdio;
    cin.tie(0),cout.tie(0);
    int n,m,s,v;
    cin>>n>>m;
    for(int i=0;i<n;i++){//无向图初始化 
    for(int j=0;j<n;j++){
    if(i!=j){
    e[i][j]=e[j][i]=inf;
    t[i][j]=t[j][i]=inf;
    }
    }
    }
    int x,y,z,w,q;
    while(m--){//读入边 
    cin>>x>>y>>z>>w>>q;
    e[x][y]=w,t[x][y]=q;
    if(!z)e[y][x]=w,t[y][x]=q;
    }
    cin>>s>>v;//起点,终点 
    for(int i=0;i<n;i++){
    d[i]=e[s][i],p[i]=t[s][i];
    }
    memset(pre,-1,sizeof(pre));
    dijkstra(n,s);
    flag=0;
    swap(d,p);swap(e,t);
    memset(vis,0,sizeof(vis));
    memset(num,0,sizeof(num));
    memset(pre2,-1,sizeof(pre2));
    dijkstra(n,s);
    int cn=0,cn2=0,road[N],road2[N],k=v,l=v;
    while(k!=-1){
    road[cn++]=k;
    k=pre[k];
    }
    while(l!=-1){
    road2[cn2++]=l;
    l=pre2[l];
    }
    int mit=d[v];//最短时间
    int mid=p[v];
    if(judge(road,cn,road2,cn2)){
    cout<<"Time = "<<mit<<"; Distance = "<<mid<<": "<<s;
    for(int i=cn-1;i>=0;i--){
    cout<<" => "<<road[i];
    }
    }else{
    cout<<"Time = "<<mit<<": "<<s;
    for(int i=cn-1;i>=0;i--){
    cout<<" => "<<road[i];
    }
    cout<<endl;
    cout<<"Distance = "<<mid<<": "<<s;
    for(int i=cn2-1;i>=0;i--){
    cout<<" => "<<road2[i];
    }
    }
    return 0;
    }
    

最后

以上就是壮观面包为你收集整理的L3-007 天梯地图(Dijkstra(两边权+一边权一点权))的全部内容,希望文章能够帮你解决L3-007 天梯地图(Dijkstra(两边权+一边权一点权))所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(82)

评论列表共有 0 条评论

立即
投稿
返回
顶部