UVA1347 旅行 Tour 題解【dp】

原題地址(vjudge)

這題還是有點意思的,你珂以理解爲要找兩條除了起點和終點之外沒有任何點是相等的路徑。這題就和某經典題不太一樣了,某經典題是可以重複的。所以用dp[i][j]dp[i][j]表示同時走到第ii個點和第jj個點就不是很好了。那怎麼表示呢?珂以用dp[i][j]dp[i][j]表示同時走到iijjmax(i,j)\max(i,j)全部都走過。易得dp[i][j]=dp[j][i]dp[i][j]=dp[j][i],規定一下所有狀態必須i>ji>j
狀態轉移方程:
dp[i][j]=min(dp[i+1][j]+dis[i][i+1],dp[i+1][i]+dis[i+1][j])dp[i][j]=min(dp[i+1][j]+dis[i][i+1],dp[i+1][i]+dis[i+1][j])
dp[i+1][j]dp[i+1][j]表示第一個人從ii+1i \to i+1,所以加上dis[i][i+1]dis[i][i+1]dp[i+1][i]dp[i+1][i]原式等於dp[i][i+1]dp[i][i+1],即從ji+1j\to i+1ii+1所有小於i的點都已走過,所以只能走到i+1),只不過要保持第一維小於第二維,所以只能轉成dp[i+1][i]dp[i+1][i],加上dis[i+1][j]dis[i+1][j],初始條件:

for(int i=1;i<=n;i++) dp[n][i]=dis[n][i]; //第一個已經到達n,所以答案爲dis[n][i]

路徑預處理:

void compare(void) 
{
	memset(dp,0,sizeof(dp)) ;
	for(int i=1;i<=n;i++) 
	{
		for(int j=1;j<=n;j++) 
		{
			double c=sqrt(abss(x[i]-x[j])*abss(x[i]-x[j])+abss(y[i]-y[j])*abss(y[i]-y[j])); //abss指絕對值
			g[i][j]=g[j][i]=c;
		}
	}
	return ;
}

狀態轉移:

for(int i=n-1;i>=2;i--) 
	{
		for(int j=1;j<i;j++) 
		{
			dp[i][j]=min(dp[i+1][j]+g[i][i+1],dp[i+1][i]+g[i+1][j]);
		}
	}

Code\color{blue}Code

# include <bits/stdc++.h>
using namespace std;
int n;
const int N=1010;
double x[N],y[N];
double g[N][N];
double dp[N][N];
double abss(double a) 
{
if(a>=0) return a;
return -a;
}
void compare(void) 
{
	memset(dp,0,sizeof(dp)) ;
	for(int i=1;i<=n;i++) 
	{
		for(int j=1;j<=n;j++) 
		{
			double c=sqrt(abss(x[i]-x[j])*abss(x[i]-x[j])+abss(y[i]-y[j])*abss(y[i]-y[j]));
			g[i][j]=g[j][i]=c;
		}
	}
	for(int i=1;i<=n;i++) dp[n][i]=g[n][i];
	return ;
}
void solve(void) 
{
	for(int i=n-1;i>=2;i--) 
	{
		for(int j=1;j<i;j++) 
		{
			dp[i][j]=min(dp[i+1][j]+g[i][i+1],dp[i+1][i]+g[i+1][j]);
		}
	}
	cout<<fixed<<setprecision(2)<<dp[2][1]+g[2][1]<<endl ;
}
int main(void) 
{
	while(~scanf("%d",&n))
	{
		for(int i=1;i<=n;i++) 
		{
			cin >> x[i] >> y[i];
		}
		compare() ;
		solve() ;

	}
	return 0;
}

nice!nice!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章