1. 程式人生 > >演算法導論第十五章習題15-1--雙調歐幾里得旅行商問題

演算法導論第十五章習題15-1--雙調歐幾里得旅行商問題

思路:1),首先將所有點加上座標,x軸指向右,y軸指向下。然後將所有點按照x軸座標從小到大排列。

2)總體思路是依次從排好序的節點取出一個節點,決定該節點應該放在第一條路徑上還是第二條路徑上。  3)定義一個數組:double b[8][8]; //b[i][j]表示第一條路徑搜尋到第i各節點,第二條路徑搜尋到第j個節點後的最短路徑長度。如果i==j則說明兩條路徑匯聚到i點上

如果i==n則說明 搜尋到終點

3)求兩點距離的方法:double Length(Node x[],int i,int j)

4)m[i][j]存的是編號 i 點與 編號 j 點的最短距離。需要宣告的是:b[i][j]=b[j][i];

所以,m矩陣是一個對稱矩陣。即 i 點與 j 點的距離跟j點與i點的矩陣相等。所以這裡我們只需要求下三角矩陣b就可以。

5)由以上思路得遞迴公式:(i>j 求的是下三角)

  (i==j時): b[i][j]=b[i][j-1]+Length[i][j-1]   
         (i>j+1時):b[i][j]= b[i-1][j]+Length[i-1][i]  
         (i=j+1時):b[i][j]=min(1<=k<j)(b[k][j]+Length[k][i]) //j==1時b[i][j]=Length(i,j);

由以上分析可以得到如下程式碼:

//雙調歐幾里得旅行商問題
#include<iostream>
#include<math.h>
#define M 65536
using namespace std;
//定義節點座標
struct Node
{
	int x;
	int y;
}N[10];
//求節點i和節點j之間的長度
double Length(Node *N,int i,int j)
{
	double L;
	L=sqrt(double((N[i].x-N[j].x)*(N[i].x-N[j].x)+(N[i].y-N[j].y)*(N[i].y-N[j].y)));
	return L;
}
void ShortPath(Node*N ,double (*b)[10],int length)
{
	int i,j,k;
	double num;
	//定義起始節點序號為1
	b[1][1]=0;
	for(i=2;i<=length;i++)
	{
		for(j=1;j<=i;j++)
		{
			//如果兩條路徑終點都是i,則總路徑的長度為一條從1到i與
			//一條從1到i-1的路徑之和加上從i-1到i的距離。
			if(i==j)
			{
				b[i][j]=b[i][j-1]+Length(N,i,j-1);
			}
			//如果i與j之間相隔一個點以上,則j點的路徑不變,而i點的路徑是
			//從1到i-1的路徑加上i-1到i的路徑
			if(i>j+1)
			{
				b[i][j]=b[i-1][j]+Length(N,i-1,i);
			}
			if(i==j+1)
			{
				b[i][j]=M;
				if(j==1)
				{
					b[i][j]=Length(N,i,j);
				}
				for(k=1;k<j;k++)
				{
					num=b[k][j]+Length(N,k,i);
					if(b[i][j]>num)
					{
						b[i][j]=num;
					}
				}
			}
			b[j][i]=b[i][j];
		}
	}
}
int main()
{
	N[1].x=0;
	N[1].y=0;
	N[2].x=1;
	N[2].y=6;
	N[3].x=2;
	N[3].y=3;
	N[4].x=5;
	N[4].y=2;
	N[5].x=6;
	N[5].y=5;
	N[6].x=7;
	N[6].y=1;
	N[7].x=8;
	N[7].y=4;
	double b[10][10]={0};
	ShortPath(N,b,7);
	cout<<b[7][7]<<endl;
	return 0;
}