uva 11374 Dijkstra (单源最短路径)

Dijkstra 的流程简介

这个算法是根据路径长度递增的思想求最短路径,单源最短路径问题,即在图中求出给定顶点到其它任一顶点的最短路径。

证明:该性质描述为:x如果P(i,j)={Vi....Vk..Vs...Vj}是从顶点i到j的最短路径,k和s是这条路径上的一个中间顶点,那么P(k,s)必定是从k到s的最短路径。下面证明该性质的正确性。   假设P(i,j)={Vi....Vk..Vs...Vj}是从顶点i到j的最短路径,则有P(i,j)=P(i,k)+P(k,s)+P(s,j)。而P(k,s)不是从k到s的最短距离,那么必定存在另一条从k到s的最短路径P'(k,s),那么P'(i,j)=P(i,k)+P'(k,s)+P(s,j)<P(i,j)。则与P(i,j)是从i到j的最短路径相矛盾。因此该性质得证。

算法流程:

小例子的演算流程:

附上白书经典的一道题目

这一题写了好久,从过年之前就开始写,现在才过,真的是被这道题卡了一年额……这是白书的题,思路不用说了,唉,直接上代码吧……

#include <iostream>
#include <stdlib.h>
#include <cstdio>
#include <vector>
#include <queue>
#include <memory.h>
#define maxn 10010
#define INF 1<<29
using namespace std;
struct Edge{
int from,to,dist;
};
struct HeapNode{
    int u,d;
    bool operator <(const HeapNode &thm)const{
        return d>thm.d;
    }
};
int m,n,N,M;
vector<Edge>edges;
vector<int>G[maxn];
int p[maxn],dist[maxn],distFirst[maxn];
bool done[maxn];
int from,to,dis,edgenum,start,end;
int path[maxn],value,final[maxn<<2],count;
void init(int N)
{
    edges.clear();
    for(int i=1;i<=N;i++)G[i].clear();
}
void AddEdge(int from,int to,int dist)
{
    edges.push_back((Edge){from,to,dist});
    m=edges.size()-1;
    G[from].push_back(m);
}
void dijkstra(int u)
{
    priority_queue<HeapNode>Q;
    memset(done,0,sizeof done);
    for(int i=1;i<=N;i++)dist[i]=INF;
    dist[u]=0;
    Q.push((HeapNode){u,0});
    while(!Q.empty())
    {
        HeapNode 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 &e=edges[G[u][i]];
            if(dist[e.to]>dist[u]+e.dist)
            {
                dist[e.to]=dist[u]+e.dist;
                p[e.to]=G[u][i];
                Q.push((HeapNode){e.to,dist[e.to]});
            }
        }
    }
}
void output(int Start,int End)
{
    if(Start==-1&&End==-1)Start=end;
    memset(final,0,sizeof final);
    count=0;int temp;
    final[++count]=Start;
    while(final[count]!=start)
    {
        temp=path[final[count]];
        Edge e = edges[temp];
        final[++count]=e.from;
    }
    if(End==-1){
        for(int i=count;i>0;i--)
            if(i==1)printf("%d\n",final[i]);
            else printf("%d ",final[i]);
        return;
    }
    for(int i=count;i>0;i--)printf("%d ",final[i]);
    count=0;final[++count]=End;
    while(final[count]!=end)
    {
        temp=p[final[count]];
        Edge e = edges[temp];
        final[++count]=e.from;
    }
    for(int i=1;i<=count;i++)
    {
        if(i==count)printf("%d\n",final[i]);
        else printf("%d ",final[i]);
    }
}
int main()
{
//    freopen("in.txt","r",stdin);
//    freopen("put.txt","w",stdout);
    bool used,kongge=0;int point;
    while(scanf("%d%d%d",&N,&start,&end)!=EOF)
    {
        if(kongge)printf("\n");
        kongge=1; int u,v,distance;
        memset(path,-1,sizeof path);
        memset(p,-1,sizeof p);
        scanf("%d",&edgenum);
        init(N);
        for(int i=0;i<edgenum;i++)
        {
            scanf("%d%d%d",&from,&to,&dis);
            AddEdge(from,to,dis);
            AddEdge(to,from,dis);
        }
        scanf("%d",&edgenum);
        dijkstra(start);
        memcpy(path,p,sizeof p);//start to end nearest distance path
        memcpy(distFirst,dist,sizeof dist);//start to end most nearest distance
        memset(p,-1,sizeof p);
        dijkstra(end);
        int StartPoint=-1,EndPoint=-1;
        value=distFirst[end];
        used=0;
        for(int i=0;i<edgenum;i++)
        {
            scanf("%d%d%d",&u,&v,&distance);
            if(value>distFirst[u]+distance+dist[v])
            {
                StartPoint=u;EndPoint=v;used=1;
                value=distFirst[u]+distance+dist[v];
            }
            if(value>distFirst[v]+distance+dist[u])
            {
                StartPoint=v;EndPoint=u;used=1;
                value=distFirst[v]+distance+dist[u];
            }
        }
        output(StartPoint,EndPoint);
        if(used)printf("%d\n",StartPoint);
        else  printf("Ticket Not Used\n");
        printf("%d\n",value);
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值