Tour (dp,紫薯第九章)

点击打开链接

.解题思路:输入按x轴排序,所以相邻两点连线总距离必短 ,注意这个结论,解释了为什么最后dp[1][2]+dist(1,2),直接加上dist(1,2)


本题看似一道几何问题,实际上可以利用动态规划解决。走一圈周长最短可以等价为两个人同时从最左端出发,沿着不同的路径走到最右端。如果定义d(i,j)表示1~max(i,j)全部走过,第一个人在i,第二个人在j,还需要走多长的距离。此时可以规定i>j,这样,还可以规定i,j中只有一个人允许走到i+1这一点。这样的话可以保证不会出现某些点跳过的情况。状态转移方程如下:

d(i,j)=min(d(i+1,j)+dist(i,i+1),d(i+1,i)+dist(j,i+1));

第二项表示为d(i+1,i)是因为已经规定i>j,又根据d(i,j)的定义易知有d(i,j)=d(j,i),因此d(i,i+1)可写为d(i+1,i)。本题的状态数有O(N^2)个,每次状态的决策只有2个,因此时间复杂度为O(N^2)。本题中由于j

#include
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
typedef pair pii;
const int INF=0x3f3f3f3f;
LL mod=1e9+7;
const int N=1005;

int n;
struct node
{
    int x,y;
}feng[N];

double dist(int i,int j) //计算两点间距离
{
    int dx= feng[i].x-feng[j].x;
    int dy= feng[i].y-feng[j].y;
    return hypot(dx,dy);
}
double dp[N][N]; // 从第一个点开始到max(i,j)的点均已走过,第一个人在i,第二个在j,还需要走多长

double solve(int i,int j)
{
    double &ans=dp[i][j];
    if(ans)
        return ans;
    if(i==n-1) //到达边界,按照约定走法,再走一步必然要到n
        return ans= dist(i,n)+dist(j,n);
    ans=min( solve(i+1,j)+dist(i,i+1) ,  solve(i+1,i)+dist(j,i+1));//两种决策,要么从i走到i+1,
                                                            //要么从j走到i+1
    return ans;
}

int main()
{
#ifndef ONLINE_JUDGE
    //freopen("in.txt","r",stdin);
#endif
    //std::ios::sync_with_stdio(false);
    //std::cin.tie(0);
    //int kase=0;
    while(cin>>n)
    {
        for(int i=1; i<=n; i++) //输入按x轴排序,所以相邻两点连线总距离必短
        {
            cin>>feng[i].x>>feng[i].y;
        }
        memset(dp,0,sizeof(dp));
        solve(1,2);
        printf("%.2lf\n",dp[1][2]+dist(1,2)); //两人从分别1,2点出发
    }
}


你可能感兴趣的:(dp,紫薯)