P3842 [TJOI2007]线段——线性dp

P3842 [TJOI2007]线段

题目描述

在一个 \(n\times n\) 的平面上,在每一行中有一条线段,第 \(i\) 行的线段的左端点是 \((i, L(i))\),右端点是 \((i, R(i))\),其中 \(1\leq L(i)\leq R(i)\leq n\)

你从 \((1, 1)\) 点出发,要求沿途走过所有的线段,最终到达 \((n, n)\) 点,且所走的路程长度要尽量短。

更具体一些说,你在任何时候只能选择向下走一步(行数增加 \(1\))、向左走一步(列数减少 \(1\))或是向右走一步(列数增加 \(1\))。当然,由于你不能向上行走,因此在从任何一行向下走到另一行的时候,你必须保证已经走完本行的那条线段。

输入格式

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

输出格式

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

输入输出样例

输入

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

输出

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\leq 20,000\)

思路

不难看出,路程长度由两个部分组成:左右走的距离 \(+\) 上下走的距离,因为上下走的距离一定是 \(n\),所以我们只需要求出左右走的最小距离即可。

很明显,当我们走完一行的线段时,我们会处在左端点/右端点,这样我们就需要在线性 \(dp\) 的基础上加一维来表示走完这一行处在左/右端点。

所以我们定义一个 \(f[i][0/1]\),表示走完第 \(i\) 行的线段后,我们处在左/右端点。

然后我们就可以用上一行的状态来推出下一行了。

分为 \(4\) 种情况:

上一行在左端点,下一行走到左端点;
上一行在左端点,下一行走到右端点;
上一行在右端点,下一行走到左端点;
上一行在右端点,下一行走到右端点;

我们以"上一行在右端点,下一行走到右端点"为例:

这样我们就可以推出状态转移方程了。

f[i][1]=min(f[i-1][1]+abs(l[i]-r[i-1])+r[i]-l[i]+1,f[i-1][0]+abs(l[i]-l[i-1])+r[i]-l[i]+1);//本行走到右端点,上一行走到左/右端点,取最小值
f[i][0]=min(f[i-1][1]+abs(r[i]-r[i-1])+r[i]-l[i]+1,f[i-1][0]+abs(r[i]-l[i-1])+r[i]-l[i]+1);//本行走到左端点,上一行走到左/右端点,取最小值

最后不要忘了初始化第 \(1\) 行就可以了。

代码

#include <bits/stdc++.h>
using namespace std;

const int maxn=2e4+50;
int n;
int l[maxn],r[maxn];
int f[maxn][2];

int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%d%d",&l[i],&r[i]);
    }
    f[1][0]=2*r[1]-l[1]-1;//第1行往返,走到右端点再回来
    f[1][1]=r[1]-1;//直接走到右端点
    for(int i=2;i<=n;i++){
        f[i][1]=min(f[i-1][1]+abs(l[i]-r[i-1])+r[i]-l[i]+1,f[i-1][0]+abs(l[i]-l[i-1])+r[i]-l[i]+1);//本行走到右端点,上一行走到左/右端点,取最小值
        f[i][0]=min(f[i-1][1]+abs(r[i]-r[i-1])+r[i]-l[i]+1,f[i-1][0]+abs(r[i]-l[i-1])+r[i]-l[i]+1);//本行走到左端点,上一行走到左/右端点,取最小值
    }
    printf("%d\n",min(f[n][1]+n-r[n],f[n][0]+n-l[n]));//因为最后还要走到(n,n)的地方,加上剩下的距离,再加上上下走的距离即可
    return 0;
}
posted @ 2020-07-12 10:38  Rubyonlу  阅读(128)  评论(0编辑  收藏  举报