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;
}