题目描述
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[j−1][i−1][1]+getdis(j,((j+i−1)+1)),dp[j−1][i−1][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][i−1][1]+getdis((j+i−2)+1,((j+i−1)+1)),dp[j][i−1][1]+getdis(j,(j+i−1)+1))
g e t d i s ( i , j ) getdis(i,j) getdis(i,j)表示从第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;
}
完结撒花★,°:.☆( ̄▽ ̄)/$:.°★ 。