UVA1347 旅行 Tour 题解【dp】

8 篇文章 0 订阅
1 篇文章 0 订阅

原题地址(vjudge)

这题还是有点意思的,你珂以理解为要找两条除了起点和终点之外没有任何点是相等的路径。这题就和某经典题不太一样了,某经典题是可以重复的。所以用 d p [ i ] [ j ] dp[i][j] dp[i][j]表示同时走到第 i i i个点和第 j j j个点就不是很好了。那怎么表示呢?珂以用 d p [ i ] [ j ] dp[i][j] dp[i][j]表示同时走到 i i i j j j max ⁡ ( i , j ) \max(i,j) max(i,j)全部都走过。易得 d p [ i ] [ j ] = d p [ j ] [ i ] dp[i][j]=dp[j][i] dp[i][j]=dp[j][i],规定一下所有状态必须 i > j i>j i>j
状态转移方程:
d p [ i ] [ j ] = m i n ( d p [ i + 1 ] [ j ] + d i s [ i ] [ i + 1 ] , d p [ i + 1 ] [ i ] + d i s [ 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][j]=min(dp[i+1][j]+dis[i][i+1],dp[i+1][i]+dis[i+1][j])
d p [ i + 1 ] [ j ] dp[i+1][j] dp[i+1][j]表示第一个人从 i → i + 1 i \to i+1 ii+1,所以加上 d i s [ i ] [ i + 1 ] dis[i][i+1] dis[i][i+1] d p [ i + 1 ] [ i ] dp[i+1][i] dp[i+1][i]原式等于 d p [ i ] [ i + 1 ] dp[i][i+1] dp[i][i+1],即从 j → i + 1 j\to i+1 ji+1 所 有 小 于 i 的 点 都 已 走 过 , 所 以 只 能 走 到 i + 1 所有小于i的点都已走过,所以只能走到i+1 ii+1),只不过要保持第一维小于第二维,所以只能转成 d p [ i + 1 ] [ i ] dp[i+1][i] dp[i+1][i],加上 d i s [ i + 1 ] [ j ] 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]);
		}
	}

C o d e \color{blue}Code 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;
}

n i c e ! nice! nice!

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值