ural1143 Electric Path (区间dp)

黑书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 205
int n;
double x[N],y[N],dis[N][N],dp[2][N][N];//0--i,1--i+len-1
int 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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值