P3842 [TJOI2007]线段

题目描述

在一个 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)。

输出格式
输出文件仅包含一个整数,你选择的最短路程的长度。 题目链接

状态表示:f[i][0] 表示走完前i行并且最终停到左端点的路程长度,f[i][1]表示停到右端点
状态计算:
f[i][0] = min(f[i-1][0] + dist(l[i-1],r[i]) + dist(r[i],l[i]) + 1, f[i-1][1] + dist(r[i-1],r[i]) + dist(r[i],l[i]) + 1);
f[i][1] = min(f[i-1][0] + dist(l[i-1],l[i]) + dist(l[i],r[i]) + 1, f[i-1][1] + dist(r[i-1],l[i]) + dist(l[i],r[i]) + 1);

代码:

#include <bits/stdc++.h>

using namespace std;

const int N = 20010;

int n;
int l[N],r[N];
int f[N][2];

int main()
{
    cin >> n;
    for(int i = 1;i <= n;i++) cin >> l[i] >> r[i];
    
    f[1][0] = r[1] - 1 + r[1] - l[1];
    f[1][1] = r[1] - 1;
    for(int i = 2;i <= n;i++)
    {
        f[i][0] = min(f[i-1][0] + abs(l[i-1]-r[i]) + r[i] - l[i], 
                      f[i-1][1] + abs(r[i-1]-r[i]) + r[i] - l[i]) + 1;
        f[i][1] = min(f[i-1][0] + abs(l[i-1]-l[i]) + r[i] - l[i],
                      f[i-1][1] + abs(r[i-1]-l[i]) + r[i] - l[i]) + 1;
    }
    cout << min(f[n][0] + n - l[n],f[n][1] + n - r[n]) << endl;
    return 0;
}
posted @ 2020-05-18 08:53  cy22  阅读(159)  评论(0编辑  收藏  举报