TSP問題——動態規划


            Traveling Salesman Problem

  Description:                    Time Limit: 4sec    Memory Limit:256MB

  有編號1到N的N個城市,問從1號城市出發,遍歷完所有的城市並最后停留在N號城市的最短路徑長度。

  Input:

  第一行整數 T :T組數據 (T<=20) 

  每個case 讀入一個N( 2 <= N <= 20),接着輸入N行,第i行有兩個整數 xi , yi 表示第 i 個城市坐標軸上的坐標 。

  Output:

  每個case輸出一個浮點數表示最短路徑。四舍五入保留兩位小數。

  Sample Input:

  1 4 0 0 1 0 1 1 0 1

  Sample Output:

  3.41

 

  經典難題!數據開到這么小就知道沒有那么簡單的復雜度了,一般的算法,即爆搜,復雜度為 o( n! ) ,我們這里采用的動態規划算法,

  算法復雜度已經從階乘級降到了o( ( n^2 )*( 2^n ) ) (看起來也是相當恐怖的,不過像這種經典難題這種復雜度對我來說已經不錯了)。

 

  開始說說思路,一開始馬上想到的必然是搜索,搜索必然超時,於是某大神直接告訴我——記憶化搜索,記憶化搜索能做的動規就能做,寫遞歸太麻煩了於是動規!

  題目中起點終點確定,我們可以考慮用一個二維dp數組來保存一個狀態——dp[i]{V}表示從結點0到結點 i 途經V中所有節點的最短路徑長(這里的V是一個集合)

  於是狀態轉移方程可以為:dp[i]{V}=min( dp[i]{V} , dist[i][j]+dp[j]{V-{j}} )  (j 屬於 V)

  

  大思路定好了,我們來考慮細節部分,主要有以下部分:

  1)建圖等等:結構體point,距離函數dist;

  2)集合V的表示:二進制數,即010表示三個數的集合第二個有,其余無;

  3)dp過程的范圍:1 ~ n-1 (最大可能為 1 ~ 18 );

  

  於是我們可以敲代碼啦!

#include <bits/stdc++.h>
const double INF=10e7;

using namespace std;

int T,n,cnt;
double a[25][25],dp[25][1100000];

struct point{		//結點結構體 
	int x,y;
}pt[25];

double d(point a,point b){		//結點間距離 
	return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}

int main()
{
	scanf("%d",&T);
	while(T--)
	{
		cnt=1;
		scanf("%d",&n);
		for(int i=2;i<n;i++) cnt<<=1;		//組合數(除起點終點外) 
		
		for(int i=0;i<n;i++)				//輸入 
			scanf("%d %d",&pt[i].x,&pt[i].y);
		
		for(int i=0;i<n;i++)				//建邊 
			for(int j=0;j<n;j++)
				a[i][j]=d(pt[i],pt[j]);
				
		for(int i=0;i<n;i++)				//初始化 
			for(int j=0;j<cnt;j++)
				dp[i][j]=INF;
		
		for(int i=0;i<n;i++)				//起點確定,定下初始條件 
			dp[i][0]=a[i][0];				
		for(int i=1;i<cnt;i++)				//從有元素考慮起 
			for(int j=1;j<n-1;j++)
			{
				for(int k=1;k<n-1;k++)
				{
					if((1<<k-1)&i)		//k is in the set
						dp[j][i]=min(dp[j][i],a[j][k]+dp[k][i-(1<<k-1)]);	//狀態轉移方程 
				}
			}
		double ans=INF;
		for(int i=1;i<n;i++)
			ans=min(ans,dp[i][cnt-1]+a[i][n-1]);
		
		printf("%.2lf\n",ans);
	}
	
	return 0;
}

  之前動態規划也是做了不少的基礎例題,這道題算是動態規划的第一次成功應用,還是蠻開心的,軟創得加油啊!

 

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM