uva11374迪杰斯特拉最短路径+打印

本文介绍了一种改进的最短路径算法实现方法,通过两次迪杰斯特拉算法分别计算起点到终点及终点到起点的距离,进而求得包含特定商业路线的最短路径。文章详细解释了算法流程,并给出了具体的代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

#include<cstdio>
#include<cstring>
#include<iostream>
#include<stack>
#include<queue>
#include<vector>
#define inf 0x3f3f3f3f
using namespace std;
const int maxn=1e3+100;
int n,k,q,s,e,m,st,en,co,sizes;
int done[maxn],d1[maxn],d2[maxn],p1[maxn],p2[maxn],cas=0,ans,sss,eee;
struct Node{
  int d,u;///d为距离,u顶点
  bool operator < (const Node& rhs) const {///重载运算符
    return d>rhs.d;
  }
};

struct edge{
  int st,en,cost;
  edge(int ss,int ee,int cc):st(ss),en(ee),cost(cc){}
};

vector<edge> e1;///经济路线
vector<int> G[maxn];///邻接边编号
vector<edge> e2;///商业路线

void init(){
  for(int i=0;i<n;i++)
    G[i].clear();
  e1.clear();
  e2.clear();
}


///p数组存放与下标对应点的直接相连的上一条边的编号,不断地e[p[]].st找前一个点,直到与起点相同。
void printE(int type,int temp,int *p){///打印从终点出发的路径
    queue<int> c;
    c.push(temp);
    int tt=p[temp];
    edge &eg=e1[tt];
    int k=temp;
    while(k!=type){
        c.push(eg.st);
        k=eg.st;
        eg=e1[p[k]];
    }
    if(c.size()>0){
        printf(" %d",c.front()+1);
        c.pop();
    }///注意输出格式,最后一个元素没有空格
    while(!c.empty()){
        printf(" %d",c.front()+1);
        c.pop();
    }
}

void printS(int type,int temp,int *p){///打印从S出发的路径
    stack<int> c;
    c.push(temp);
    int tt=p[temp];
    edge &eg=e1[tt];
    int k=temp;
    while(k!=type){
        c.push(eg.st);
        k=eg.st;
        eg=e1[p[k]];
    }
    if(c.size()>0){
        printf("%d",c.top()+1);
        c.pop();
    }
    while(!c.empty()){
        printf(" %d",c.top()+1);
        c.pop();
    }
}

void dj(int s,int *d,int *p){
  priority_queue<Node> q;
  for(int i=0;i<n;i++)
    d[i]=inf;
    d[s]=0;
    for(int i=0;i<n;i++)
  memset(done,0,sizeof(done));
  q.push(Node{0,s});
  while(!q.empty()){
    Node x=q.top();
    q.pop();
    int u=x.u;
    if(done[u])
        continue;
    done[u]=true;
    for(int i=0;i<G[u].size();i++){
        edge &ed=e1[G[u][i]];
        if(d[ed.en]>d[u]+ed.cost){
            d[ed.en]=d[u]+ed.cost;
            p[ed.en]=G[u][i];
            q.push(Node{d[ed.en],ed.en});
        }
    }
  }
}

int main(){
   while(scanf("%d%d%d",&n,&s,&e)!=EOF){
    if(cas++)
        printf("\n");
    init();
    s--,e--;
    sss=eee=-1;
    scanf("%d",&m);
    for(int i=0;i<m;i++){
        scanf("%d%d%d",&st,&en,&co);
        e1.push_back(edge(st-1,en-1,co));///双向路线
        e1.push_back(edge(en-1,st-1,co));
        sizes=e1.size();
        G[st-1].push_back(sizes-2);///G中边的序号要对应上e1的下标
        G[en-1].push_back(sizes-1);
    }
    dj(s,d1,p1);///从s出发找到终点的最短路径
    dj(e,d2,p2);///从e出发找到起点的最短路径
    scanf("%d",&k);
    for(int i=0;i<k;i++){
        scanf("%d%d%d",&st,&en,&co);
        e2.push_back(edge(st-1,en-1,co));
        e2.push_back(edge(en-1,st-1,co));
    }
    ans=d1[e];
    for(int i=0;i<e2.size();i++){
        int start=e2[i].st;
        int fi=e2[i].en;
        int time=e2[i].cost;
        if(ans>d1[start]+time+d2[fi]){
            ans=d1[start]+time+d2[fi];
            sss=start;
            eee=fi;
        }
        if(ans>d1[fi]+time+d2[start]){
            ans=d1[fi]+time+d2[start];
            sss=fi;
            eee=start;
        }
    }
    if(eee==-1){
        printS(s,e,p1);
        printf("\n");
        printf("Ticket Not Used\n%d\n",ans);
    }
    else{
        printS(s,sss,p1);
        printE(e,eee,p2);
        printf("\n");
        printf("%d\n",sss+1);
        printf("%d\n",ans);
    }
   }
   return 0;
}

这道题开始想到的方法是从起点比较复杂,最后打印路径炒鸡麻烦。不过这也提醒了我头不能太铁,对于计算时间或距离的没有方向的标量,是可以把过程反过来的。像这道题,从起点出发到终点,中间换线的过程,可以看作是从起点到中转站上车点,经过商业线到商业线终点,最后从终点到商业线终点z 这样就可以直接两次迪杰斯特拉,分别是起点到终点,终点到起点,然后再把距离相加就可以。(开始我是多次迪杰斯特拉。。真是笨)

然后就是路径的输出,由于p数组存储的是与下标对应点直接相连的上一条边,所以不断的压栈找到起点,然后输出。如果是从e出发,对应的就是队列。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值