【紫书】(UVa1347)Tour

来源:互联网 发布:添加windows凭据 编辑:程序博客网 时间:2024/05/22 08:21

继续考虑dp题目。

题意分析

其实这里只是更加仔细的做一个lrj的复读机(Orz
他分析了一个很重要的结果:如果是一个人从左到右再回来,并且每个点恰经过一次,那么等价于两个人从左到右每个点经过一次地遍历这些点。因为这样,我们才能够得到d[i,j]这样的方法来记录值。
但是这样也不够。d[i,j]我们最开始得到的是比较简单的记录状态:A走到i,B走到j得到的最小距离——那我怎么知道A和B会不会重复的走?(i,j)能不能转移到(i+1,j)?我们的状态里面没有保存这个结论。也就是说,这个状态定义的不好。
因此,我们定义成这样:把原来的状态表示成1max(i,j)的点全部走过的情况下两人能够得到的最小值。那么状态的转移就很显然了。考虑到d(i,j)=d(j,i),规定i>j。直接就可以得到d(i,j)=min(d(i+1,j)+dist(i,i+1),d(i+1,i)+dist(j,i+1))
这样会不会漏解呢?不会。如果i能够直接走到i+2,那么根据定义就无法走到i+1了。因此,我们让j走到i+1,是能够做到不遗漏的——因为我们之前考虑的情况不存在。
从上面不是我的分析可以看出,一个对题目深入分析得到的状态对dp题目的解决多么重要。

代码

很神秘,我用记忆化搜索写了半天,tle了六次……可能真的是有效率问题。以我现在的水平搞不明白是怎么回事,以后再解决吧。但是这里用循环不困难。

#include <cstring>#include <algorithm>#include <cstdio>#include <cstdlib>#include <iostream>#include <cmath>#include <queue>#include <set>#include <iomanip>#include <vector>#define ZERO(x) memset((x),0,sizeof(x))using namespace std;//const int maxn=;int x[1005],y[1005];double dp[1005][1005];double dist[1005][1005];double inf;int n;int main(){    while(scanf("%d",&n)==1)    {        memset(dp,0x43,sizeof(dp));        inf=dp[0][0];        for(int i=1;i<=n;++i)            scanf("%d%d",&x[i],&y[i]);        for(int i=1;i<=n;++i)            for(int j=1;j<i;++j)                dist[j][i]=dist[i][j]=sqrt((x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]));        for(int i=n-1;i>=1;--i)            for(int j=1;j<i;++j)                if(i==n-1) dp[i][j]=dist[i][n]+dist[j][n];                 else dp[i][j]=min(dp[i+1][j]+dist[i][i+1],dp[i+1][i]+dist[i+1][j]);        printf("%.2lf\n",dp[2][1]+dist[1][2]);    }    return 0;}
原创粉丝点击