Dijkstra演算法,求最短路(dp 動態規劃)
阿新 • • 發佈:2018-12-24
•迪傑斯特拉(Dijkstra)演算法思想
按路徑長度遞增次序產生最短路徑演算法:
把V分成兩組:
(1)S:已求出最短路徑的頂點的集合
(2)V-S=T:尚未確定最短路徑的頂點集合
將T中頂點按最短路徑遞增的次序加入到S中,
保證:(1)從源點V0到S中各頂點的最短路徑長度都不大於
從V0到T中任何頂點的最短路徑長度
(2)每個頂點對應一個距離值
S中頂點:從V0到此頂點的最短路徑長度
T中頂點:從V0到此頂點的只包括S中頂點作中間
頂點的最短路徑長度
依據:可以證明V0到T中頂點Vk的最短路徑,或是從V0到Vk的
直接路徑的權值;或是從V0經S中頂點到Vk的路徑權值之和
(反證法可證)
•求最短路徑步驟 –初使時令 S={V0},T={其餘頂點},T中頂點對應的距離值 »若存在<V0,Vi>,為<V0,Vi>弧上的權值 »若不存在<V0,Vi>,為µ –從T中選取一個其距離值為最小的頂點W,加入S –對T中頂點的距離值進行修改:若加進W作中間頂點,從V0到Vi的距離值比不加W的路徑要短,則修改此距離值 –重複上述步驟,直到S中包含所有頂點,即S=V為止•演算法實現 –圖用帶權鄰接矩陣儲存ad[][] –陣列dist[]存放當前找到的從源點V0到每個終點的最短路徑長度,其初態為圖中直接路徑權值 –陣列pre[]表示從V0到各終點的最短路徑上,此頂點的前一頂點的序號;若從V0到某終點無路徑,則用0作為其前一頂點的序號
§
程式碼實現:
/*Dijkstra求單源最短路徑 */ #include <iostream> #include<stdlib.h> #include<stack> #define M 100 #define N 100 using namespace std; typedef struct node { int matrix[N][M]; //鄰接矩陣 int n; //頂點數 int e; //邊數 }MGraph; void DijkstraPath(MGraph g,int *dist,int *path,int v0) //v0表示源頂點 { int i,j,k; bool *visited=(bool *)malloc(sizeof(bool)*g.n); for(i=0;i<g.n;i++) //初始化 { if(g.matrix[v0][i]>0&&i!=v0) { dist[i]=g.matrix[v0][i]; path[i]=v0; //path記錄最短路徑上從v0到i的前一個頂點 } else { dist[i]=INT_MAX; //若i不與v0直接相鄰,則權值置為無窮大 path[i]=-1; } visited[i]=false; path[v0]=v0; dist[v0]=0; } visited[v0]=true; for(i=1;i<g.n;i++) //迴圈擴充套件n-1次 { int min=INT_MAX; int u; for(j=0;j<g.n;j++) //尋找未被擴充套件的權值最小的頂點 { if(visited[j]==false&&dist[j]<min) { min=dist[j]; u=j; } } visited[u]=true; for(k=0;k<g.n;k++) //更新dist陣列的值和路徑的值 { if(visited[k]==false&&g.matrix[u][k]>0&&min+g.matrix[u][k]<dist[k]) { dist[k]=min+g.matrix[u][k]; path[k]=u; } } } } void showPath(int *path,int v,int v0) //列印最短路徑上的各個頂點 { stack<int> s; int u=v; while(v!=v0) { s.push(v); v=path[v]; } s.push(v); while(!s.empty()) { cout<<s.top()<<" "; s.pop(); } } int main(int argc, char *argv[]) { int n,e; //表示輸入的頂點數和邊數 while(cin>>n>>e&&e!=0) { int i,j; int s,t,w; //表示存在一條邊s->t,權值為w MGraph g; int v0; int *dist=(int *)malloc(sizeof(int)*n); int *path=(int *)malloc(sizeof(int)*n); for(i=0;i<N;i++) for(j=0;j<M;j++){ g.matrix[i][j]=0; g.n=n; g.e=e; } for(i=0;i<e;i++) { cin>>s>>t>>w; g.matrix[s][t]=w; } cin>>v0; //輸入源頂點 DijkstraPath(g,dist,path,v0); for(i=0;i<n;i++) { if(i!=v0) { showPath(path,i,v0); cout<<dist[i]<<endl; } } } system("pause"); return 0; }
另一種寫法:
#include<iostream>
#include<vector>
#include<algorithm>
#include<queue>
#include<cstring>
#include<cmath>
#define INF 0x3f3f3f3f
using namespace std;
const int MAX = 105;
int n,m;//n個點,m條邊;
int st,en;//存起點和終點
vector<int >edge[MAX]; //存與之相連的點
int length [MAX][MAX];//存邊的長度
int dis[MAX];
bool vis[MAX];
struct Node{
int point,distance;
bool friend operator <(Node a,Node b){
return a.distance > b.distance;
}
}pr,np;
void dijkstra(){
memset(dis,INF,sizeof(dis));
memset(vis,false,sizeof(vis));
dis[st]=0;
priority_queue<Node> Q;
pr.point=st;
pr.distance=0;
Q.push(pr);
while(!Q.empty()){
pr=Q.top();
Q.pop();
// cout<<"==="<<pr.point<<endl;
if(vis[pr.point]||pr.point==en)
continue;
vis[pr.point]=true;
for(int i=0;i<edge[pr.point].size();i++){
np.point=edge[pr.point][i];
np.distance=pr.distance+length[pr.point][np.point];
if(np.distance < dis[np.point]){
dis[np.point]=np.distance;
Q.push(np);
}
}
}
}
int main(){
while(cin>>n>>m&&(n||m)){
st=1;
en=n;
memset(length,INF,sizeof(length));
for(int i=0;i<m;i++){
int x,y,z;
cin>>x>>y>>z;
edge[x].push_back(y);//存雙向邊
edge[y].push_back(x);
if(length[x][y]>z)
length[x][y]=length[y][x]=z;
}
dijkstra();
cout<<dis[en]<<endl;
}
return 0;
}