UVA 1347 Tour(DP) 紫书训练

题目链接:UVA 1347
做题感受:看到题自己想没啥思路,也想不出将一人来回改成两人同时走到终点,自己本来的想法是构造一个三维数组dp[i][j][0]和dp[i][j][1]分别表示过去和回来的状态,但是写到后面发现状态转移方程写不出来,不知道该怎么转移,感觉主要还是状态转移方程太难写,结合lrj的分析和别人的博客分析最后才勉强写出来了。(其实我真没看出来这跟DAG有特别大关系,我就觉得勉勉强强搭上边)

(感觉思路分析太长的还是直接看概括吧,个人感觉自己思路分析写的不太好)
思路:
紫书上写的挺明白了,其实就是把一个人来回分成两个人同时到达终点,但是要怎么定义状态呢?我们定义dp(i,j)为第一个人在i点,第二个人在j点时,离终点还有多远,先不用管他怎么表示多远,dp(i,j)和dp(j,i)实际上是一样的,无非就是表示成第二个人在i点,第一个人在j点,其实答案没有区别,因此我们默认i>j,
这样一来,我们可以将dp(i,j)定义为前面i个点都走过了,还需要走多远才能到达终点,这样定义之后,不管是哪个人,下一步只能走到i+1,i+2,i+3…以此类推,i+1没问题,就走一步就好了,如果是走到i+2或3就会发现i+1没走过(因为下一步i=i+2只能走到i+2以后的点,另一个人下一步也不能到达i+1这个点),那该怎么办,那我们就定义下一步只能走到i+1的位置,这样定义就可以保证每个点都会走过,其实之前你直接走到i+2只有一步,我们现在就是把i+2分成了2步,每次都是i+1保证所有点都能到达(假如a没走过的点,b会帮忙补上)(其实也就是在状态转移的时候要么是dp(i+1,i)要么是dp(i+1,j),看谁补上来)
然后就得出了状态转移方程
dp(i,j)=min(dp(i+1,j)+d(i,i+1),dp(i+1,i)+d(i+1,i)+d(j,i+1)).
最后就是要设定好边界条件dp[n-1][x]表示即将到达终点,所有点都走过了,只要两人各走一步就走到终点.

简要概括思路:一人分成两人,将状态定义为dp(i,j),每次只能让两个人中的一个能走到i+1的位置(把很长的一步分成一个个小步,每次只到下一个点),设定好边界dp[n-1][x],最后得出状态转移方程dp(i,j)=min(dp(i+1,j)+d(i,i+1),dp(i+1,i)+d(i+1,i)+d(j,i+1)).
d表示距离,dp用来递归.

下面是我的代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int inf = 0x3f3f3f3f;
int n;
double dp[1005][1005];//表示a在第i个位置,b在第j个位置的时候距离终点还有多远
struct dian {
  double x, y;
 dian(double x = 0,double y = 0):x(x),y(y){}//这条没啥用,可以无视
}a[205];
double d(int i, int j)//计算两点间距离
{
    return sqrt((a[i].x - a[j].x) * (a[i].x - a[j].x) + (a[i].y - a[j].y) * (a[i].y - a[j].y));
}
double jie(int i, int j)//递归dp
{
    if (dp[i][j] > 0)return dp[i][j];
    return dp[i][j] = min(jie(i + 1, j) + d(i,i+1), jie(i + 1, i) + d(j,i+1));
}
int main()
{
    int i, j;
    while (scanf("%d",&n)!=EOF)
    {
        memset(dp, 0, sizeof(dp));
        for (i = 1; i <= n; i++)
        {
            cin >>a[i].x >> a[i].y;
        }
        for (i = 1; i < n-1; i++)
        {
            dp[n - 1][i] = d(n-1,n)+d(i,n);//先将边界的值定义好
        }
        double ans = jie(1, 1);//引用递归函数
        printf("%.2f\n",ans);
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值