1. 程式人生 > >最短路徑問題 動態規劃

最短路徑問題 動態規劃

    問題參考:   

       現有一張地圖,各結點代表城市,兩結點間連線代表道路,線上數字表示城市間的距離。如圖1所示,試找出從結點A到結點E的最短距離。


我們可以用深度優先搜尋法來解決此問題,該問題的遞迴式為

其中是與v相鄰的節點的集合,w(v,u)表示從v到u的邊的長度。

這個程式的效率如何呢?我們可以看到,每次除了已經訪問過的城市外,其他城市都要訪問,所以時間複雜度為O(n!),這是一個“指數級”的演算法。

首先,我們來觀察一下這個演算法。在求從B1到E的最短距離的時候,先求出從C2到E的最短距離;而在求從B2到E的最短距離的時候,又求了一遍從C2到E的最短距離。也就是說,從C2到E的最短距離我們求了兩遍。同樣可以發現,在求從C1、C2到E的最短距離的過程中,從D1到E的最短距離也被求了兩遍。而在整個程式中,從D1到E的最短距離被求了四遍。如果在求解的過程中,同時將求得的最短距離"記錄在案",隨時呼叫,就可以避免這種情況。於是,可以改進該演算法,將每次求出的從v到E的最短距離記錄下來,在演算法中遞迴地求MinDistance(v)時先檢查以前是否已經求過了MinDistance(v),如果求過了則不用重新求一遍,只要查詢以前的記錄就可以了。這樣,由於所有的點有n個,因此不同的狀態數目有n個,該演算法的數量級為O(n)。

更進一步,可以將這種遞迴改為遞推,這樣可以減少遞迴呼叫的開銷。

程式碼如下:

#include <iostream>
#include <fstream>
using namespace std;

ifstream fin("in.txt");
#define maxLength 20

int matrix[maxLength][maxLength];   //有向圖的鄰接表
int minPath[maxLength];             //儲存這每個節點到終點的最短路徑
int trace[maxLength];               //記錄下最短線路
int v_n; //節點個數

int MinDistance(int v)
{
	if(minPath[v]>0) return minPath[v]; 
	if(v==v_n-1) return 0;     //邊界值
	int min=1000,t,j;
	for(int i=v+1;i<v_n;i++)
	{
		if(matrix[v][i]>0) 
		{	
			t = matrix[v][i]+MinDistance(i);
			if(min>t){ min=t; j=i;}
		}
	}
	minPath[v]=min;
	trace[v]=j;
	return minPath[v];
}

int main()
{
	
	fin>>v_n;
	for(int i=0;i<v_n;i++)
	{
		for(int j=0;j<v_n;j++)
		{
			fin>>matrix[i][j];
			cout<<matrix[i][j]<<"-";
		}
		cout<<endl;
	}
	memset(minPath,0,sizeof(int)*maxLength);
	memset(trace,0,sizeof(int)*maxLength);
	int minD = MinDistance(0);
	cout<<"最短路徑:"<<minD<<endl;
	i=0;
	cout<<"1-->";
	while(minD>0)
	{
		cout<<trace[i]+1<<"-->";
		minD = minD-matrix[i][trace[i]];
		i = trace[i];
	}
	cout<<endl;
	return 0;
}

   輸入檔案:in.txt 

(例子來源於《演算法設計與分析》(夏紅霞 主編)教材147頁例題)

12
0 9 7 3 2 0 0 0 0 0 0 0
0 0 0 0 0 4 2 1 0 0 0 0
0 0 0 0 0 2 7 0 0 0 0 0
0 0 0 0 0 0 0 11 0 0 0 0
0 0 0 0 0 0 11 8 0 0 0 0
0 0 0 0 0 0 0 0 6 5 0 0
0 0 0 0 0 0 0 0 5 3 0 0
0 0 0 0 0 0 0 0 0 5 6 0
0 0 0 0 0 0 0 0 0 0 0 4
0 0 0 0 0 0 0 0 0 0 0 2
0 0 0 0 0 0 0 0 0 0 0 5
0 0 0 0 0 0 0 0 0 0 0 0

輸出檔案:

0-9-7-3-2-0-0-0-0-0-0-0-
0-0-0-0-0-4-2-1-0-0-0-0-
0-0-0-0-0-2-7-0-0-0-0-0-
0-0-0-0-0-0-0-11-0-0-0-0-
0-0-0-0-0-0-11-8-0-0-0-0-
0-0-0-0-0-0-0-0-6-5-0-0-
0-0-0-0-0-0-0-0-5-3-0-0-
0-0-0-0-0-0-0-0-0-5-6-0-
0-0-0-0-0-0-0-0-0-0-0-4-
0-0-0-0-0-0-0-0-0-0-0-2-
0-0-0-0-0-0-0-0-0-0-0-5-
0-0-0-0-0-0-0-0-0-0-0-0-
最短路徑:16
1-->2-->7-->10-->12-->
Press any key to continue