新年趣事之红包 题解

题目描述

xiaomengxian一进门,发现外公、外婆、叔叔、阿姨……都坐在客厅里等着他呢。经过仔细观察,xiaomengxian发现他们所有人正好组成了一个凸多边形。最重要的是,他们每个人手里都拿着一个红包( ^ o ^ )。于是非常心急,xiaomengxian决定找一条最短的路线,拿到所有的红包。 假设屋里共有N个人拿着红包,把他们分别从1到N编号。其中,编号为1的人就坐在大门口,xiaomengxian必须从这里出发去拿其它的红包。一条合法的路线必须经过所有的点一次且仅一次。

输入格式

第一行为一个整数N(1<=N<=800)。 以下N行,每行两个实数Xi,Yi,表示该点的坐标。 各个点按照逆时针顺序依次给出。

输出格式

一个实数,表示最短的路线长度(保留三位小数)。

输入样例

4
50.0 1.0
5.0 1.0
0.0 0.0
45.0 0.0

输出样例

50.211

这是一道线性动态规划的题目。

这题有一个细节:题目给出的点连起来是凸多边形(xiaomengxian发现他们所有人正好组成了一个凸多边形)。

根据这个细节,我们可以推出来一个结论:题目要求的最短路径互相没有交点,否则就不是最短路径了

为什么呢?

因为我们要选的是最短路,如果一个点访问了两次就不是最短路了,而两条边相交,相交的那个点就访问了两次,就不可能是最短路了

最好怎么走呢,每次都往上面或者下面没被走过的第一个点走。
比如这样

或者这样

在这里插入图片描述
这样才能保证走过的路径没有交点,并且最小。

d p [ i ] [ j ] [ 0 , 1 ] dp[i][j][0,1] dp[i][j][0,1]走了 i i i个点,往上面走了 j j j个点,最后一维表示当前我在上面还是下面。

d p [ j ] [ i ] [ 0 ] = m i n ( d p [ j − 1 ] [ i − 1 ] [ 1 ] + g e t d i s ( j , ( ( j + i − 1 ) + 1 ) ) , d p [ j − 1 ] [ i − 1 ] [ 1 ] + g e t d i s ( j , j + 1 ) ) ; dp[j][i][0] = min(dp[j - 1][i - 1][1] + getdis(j, ((j + i - 1) + 1)), dp[j - 1][i - 1][1] + getdis(j, j + 1)); dp[j][i][0]=min(dp[j1][i1][1]+getdis(j,((j+i1)+1)),dp[j1][i1][1]+getdis(j,j+1));

d p [ j ] [ i ] [ 1 ] = m i n ( d p [ j ] [ i − 1 ] [ 1 ] + g e t d i s ( ( j + i − 2 ) + 1 , ( ( j + i − 1 ) + 1 ) ) , d p [ j ] [ i − 1 ] [ 1 ] + g e t d i s ( j , ( j + i − 1 ) + 1 ) ) dp[j][i][1] = min(dp[j][i - 1][1] + getdis((j + i - 2) + 1, ((j + i - 1) + 1)), dp[j][i - 1][1] + getdis(j, (j + i - 1) + 1)) dp[j][i][1]=min(dp[j][i1][1]+getdis((j+i2)+1,((j+i1)+1)),dp[j][i1][1]+getdis(j,(j+i1)+1))

g e t d i s ( i , j ) getdis(i,j) getdis(ij)表示从第i个点到第j个点的距离,用了勾股定理

 #include <bits/stdc++.h>
using namespace std;
#define MAXN 1005
int n;
double x[MAXN], y[MAXN];
double dp[MAXN][MAXN][2];
double getdis(int i, int j)
{
    
    
    return sqrt((x[i] - x[j]) * (x[i] - x[j]) + (y[i] - y[j]) * (y[i] - y[j]));
}
int main()
{
    
    
	scanf("%d", &n);
    for(int i = 1; i <= n; i++)
        scanf("%lf %lf", &x[i], &y[i]);
    for(int i = 1; i < n; i++)
    {
    
    
        for(int j = 1; j <= n; j++)
        {
    
    
            dp[j][i][0] = min(dp[j % n + 1][i - 1][1] + getdis(j, ((j + i - 1) % n + 1)), dp[j % n + 1][i - 1][1] + getdis(j, j % n + 1));
            dp[j][i][1] = min(dp[j][i - 1][1] + getdis((j + i - 2) % n + 1, ((j + i - 1) % n + 1)), dp[j][i - 1][1] + getdis(j, (j + i - 1) % n + 1)); 
        }
    }
    double ans = 999999999;
    for(int i = 1; i <= n; i++)
        ans = min(ans, min(dp[i][n - 1][0], dp[i][n - 1][1]));
    printf("%.3lf\n",ans);
    return 0;
}
 

完结撒花★,°:.☆( ̄▽ ̄)/$:.°★

猜你喜欢

转载自blog.csdn.net/CoderZeng/article/details/109049902