Tour (dp,紫薯第九章)

2 篇文章 0 订阅

点击打开链接

.解题思路:输入按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<i,因此还可以提前计算好所有j<i的距离,这样可以避免重复计算距离,进一步提升效率。

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int,int> 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点出发
    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值