1. 程式人生 > >Dijkstra演算法,求最短路(dp 動態規劃)

Dijkstra演算法,求最短路(dp 動態規劃)

迪傑斯特拉(Dijkstra)演算法思想

按路徑長度遞增次序產生最短路徑演算法:

V分成兩組:

(1)S已求出最短路徑的頂點的集合

(2)V-S=T尚未確定最短路徑的頂點集合

T中頂點按最短路徑遞增的次序加入到S中,

保證:(1)從源點V0S中各頂點的最短路徑長度都不大於

                      從V0T中任何頂點的最短路徑長度

            (2)每個頂點對應一個距離值

S中頂點:從V0到此頂點的最短路徑長度

T中頂點:從V0到此頂點的只包括S中頂點作中間

                                      頂點的最短路徑長度

依據:可以證明V0T中頂點Vk的最短路徑,或是從V0Vk

            直接路徑的權值;或是從V0S中頂點到Vk的路徑權值之和

(反證法可證)

求最短路徑步驟 初使時令 S={V0},T={其餘頂點},T中頂點對應的距離值 »若存在<V0,Vi>,為<V0,Vi>弧上的權值 »若不存在<V0,Vi>µ T中選取一個其距離值為最小的頂點W,加入S T中頂點的距離值進行修改:若加進W作中間頂點,從V0Vi的距離值比不加W的路徑要短,則修改此距離值 重複上述步驟,直到S中包含所有頂點,即S=V為止
•演算法實現 –圖用帶權鄰接矩陣儲存ad[][] –陣列dist[]存放當前找到的從源點V0到每個終點的最短路徑長度,其初態為圖中直接路徑權值 –陣列pre[]表示從V0到各終點的最短路徑上,此頂點的前一頂點的序號;若從V0到某終點無路徑,則用0作為其前一頂點的序號
§
每一對頂點之間的最短路徑 •方法一:每次以一個頂點為源點,重複執行Dijkstra演算法n次—— T(n)=O(n³) •方法二:弗洛伊德(Floyd)演算法 –演算法思想:逐個頂點試探法 –求最短路徑步驟 »初始時設定一個n階方陣,令其對角線元素為0,若存在弧<Vi,Vj>,則對應元素為權值;否則為µ »逐步試著在原直接路徑中增加中間頂點,若加入中間點後路徑變短,則修改之;否則,維持原值 »所有頂點試探完畢,演算法結束



程式碼實現:

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