ural1143 Electric Path (区间dp)

来源:互联网 发布:浪潮软件重大新闻 编辑:程序博客网 时间:2024/06/06 08:55

黑书1.5.2 例题7 青蛙的烦恼
没找到原题,这个题和原题差不多吧,就是没规定从1开始,可以从任意点开始,难了一点点吧。首先可以证明:最短路径一定没有交叉边,否则还可以更短。这就要求我们i点,只可能跳到i+1,i+len-1两点。这样就有了最优子结构,用dp[0][i][len]表示从i开始,遍历{i..i+len-1}中的顶点一次且仅一次的最短距离。dp[1][i][len]表示从i+len-1开始,遍历{i..i+len-1}中的顶点一次且仅一次的最短距离。则状态转移方程为:
dp[0][i][len]=min(dp[0][i+1][len1]+dis[i][i+1],dp[1][i+1][len1]+dis[i][i+len1]);
dp[1][i][len]=min(dp[1][i][len1]+dis[i+len1][i+len2],dp[0][i][len1]+dis[i][i+len1]);
答案为min{dp[0][i][n]|1in}复杂度是O(n2)

#include <cstdio>#include <cstring>#include <cmath>#include <iostream>using namespace std;#define N 205int n;double x[N],y[N],dis[N][N],dp[2][N][N];//0--i,1--i+len-1int main(){//  freopen("a.in","r",stdin);    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)            dis[i][j]=sqrt((x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]));    for(int i=1;i<=n;++i) dp[1][i][1]=dp[0][i][1]=0;    for(int len=2;len<=n;++len)        for(int i=1;i<=n;++i){            dp[0][i][len]=min(dp[0][(i+1-1)%n+1][len-1]+dis[i][(i+1-1)%n+1],dp[1][(i+1-1)%n+1][len-1]+dis[i][(i+len-1-1)%n+1]);            dp[1][i][len]=min(dp[1][i][len-1]+dis[(i+len-1-1)%n+1][(i+len-2-1)%n+1],dp[0][i][len-1]+dis[i][(i+len-1-1)%n+1]);        }    double ans=1000000000.0;    for(int i=1;i<=n;++i) if(dp[0][i][n]<ans) ans=dp[0][i][n];    printf("%.3lf\n",ans);    return 0;}
原创粉丝点击