洛谷 P3842 [TJOI2007]线段 DP

给一个 n × n n\times n n×n 的平面,每一行有一个线段,左右端点 ( i , L ( i ) ) , ( i , R ( i ) ) (i,L(i)),(i,R(i)) (i,L(i)),(i,R(i)) ,满足 1 ≤ L ( i ) ≤ R ( i ) ≤ n 1\le L(i)\le R(i)\le n 1L(i)R(i)n

( 1 , 1 ) (1,1) (1,1) 出发,要求走过所有线段,到达 ( n , n ) (n,n) (n,n) ,要求总路程尽可能短。

每次只能向下/左/右,每行的线段要走走完。

思路:用 f [ i ] [ 0 ] f[i][0] f[i][0] 表示走完 i i i 行后停留在左端点的最少步数, f [ i ] [ 1 ] f[i][1] f[i][1] 表示走完 i i i 行后停留在右端点的最少步数。

举一半例子:

f [ i ] [ 0 ] = min ⁡ ( f [ i − 1 ] [ 0 ] + a b s ( l [ i − 1 ] − r [ i ] ) + r [ i ] − l [ i ] + 1 ,    f [ i − 1 ] [ 1 ] + a b s ( r [ i − 1 ] − r [ i ] ) + r [ i ] − l [ i ] + 1 ) \begin{aligned} f[i][0]=\min&(f[i-1][0]+abs(l[i-1]-r[i])+r[i]-l[i]+1,\\ &\;f[i-1][1]+abs(r[i-1]-r[i])+r[i]-l[i]+1) \end{aligned} f[i][0]=min(f[i1][0]+abs(l[i1]r[i])+r[i]l[i]+1,f[i1][1]+abs(r[i1]r[i])+r[i]l[i]+1)

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#define MAXN 20010
using namespace std;
int n,l[MAXN],r[MAXN],f[MAXN][2],res;
int main(){
#ifdef WINE
    freopen("data.in","r",stdin);
#endif
    scanf("%d",&n);
    for(int i=1;i<=n;i++)scanf("%d%d",&l[i],&r[i]);
    f[1][0]=r[1]-l[1]+r[1]-1; // 初始化
    f[1][1]=r[1]-1;
    for(int i=2;i<=n;i++){
        f[i][0]=min(f[i-1][0]+abs(r[i]-l[i-1]),f[i-1][1]+abs(r[i]-r[i-1]))+r[i]-l[i]+1;
        f[i][1]=min(f[i-1][0]+abs(l[i]-l[i-1]),f[i-1][1]+abs(l[i]-r[i-1]))+r[i]-l[i]+1;
    }
    res=min(f[n][0]+n-l[n],f[n][1]+n-r[n]);
    printf("%d\n",res);
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值