[TJOI2007]segment

题目描述

在一个 n*n 的平面上,在每一行中有一条线段,第 i 行的线段的左端点是(i, L(i)),右端点是(i, R(i)),其中 1 ≤ L(i) ≤ R(i) ≤ n。
你从(1, 1)点出发,要求沿途走过所有的线段,最终到达(n, n)点,且所走的路程长度要尽量短。
更具体一些说,你在任何时候只能选择向下走一步(行数增加 1)、向左走一步(列数减少 1)或是向右走一步(列数增加 1)。当然,由于你不能向上行走,因此在从任何一行向下走到另一行的时候,你必须保证已经走完本行的那条线段。

输入输出格式

输入格式:

输入文件的第一行有一个整数 n,以下 n 行,在第 i 行(总第(i+1)行)的两个整数表示L(i)和 R(i)。

输出格式:

输出文件仅包含一个整数,你选择的最短路程的长度。

输入输出样例

输入样例#1:

6
2 6
3 4
1 3
1 2
3 6
4 5

输出样例#1:

24

说明

我们选择的路线是
(1,1) (1,6)
(2,6) (2, 3)
(3, 3) (3, 1)
(4, 1) (4, 2)
(5, 2) (5, 6)
(6, 6) (6, 4) (6, 6)
不难计算得到,路程的总长度是 24。 100%的数据中,n ≤ 20 000。

一眼看上去是一个dp题
对于这个题目
在一行中
我们要么从左至右走完这行的线段
要么从右至左走完这行的线段
所以转移方程就很好写了
1119251-20171202112650604-81454078.png

#include<iostream>
#include<cstdlib>
#include<cstdio>
#define N 20005
using namespace std;

struct line{
    int l,r,len;
}q[N];

int f[N][5],n,ans;

int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%d%d",&q[i].l,&q[i].r);
        q[i].len=q[i].r-q[i].l;
    }
    f[1][1]=q[1].l-1;
    f[1][3]=q[1].r-1;
    f[1][2]=q[1].len+f[1][3];
    f[1][4]=q[1].len+f[1][1];
    for(i=2;i<=n;i++){
        f[i][1]=min(f[i-1][2]+abs(q[i-1].l-q[i].l)+1,f[i-1][4]+abs(q[i-1].r-q[i].l)+1);
        f[i][3]=min(f[i-1][2]+abs(q[i-1].l-q[i].r)+1,f[i-1][4]+abs(q[i-1].r-q[i].r)+1);
        f[i][2]=f[i][3]+q[i].len;
        f[i][4]=f[i][1]+q[i].len;
    }
    ans=min(n-q[n].l+f[n][2],n-q[n].r+f[n][4]);
    printf("%d\n",ans);
    return 0;
}

转载于:https://www.cnblogs.com/qdscwyy/p/7953758.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值