【洛谷 P3842 [TJOI2007]线段】解题报告(动态规划)

题面

在一个 \(n\times n\) 的平面上,在每一行中有一条线段,第 \(i\) 行的线段的左端点是 \((i, L_i)\),右端点是 \((i, R_i)\)

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

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

\(1\le n\le 2\times 10^4\)\(1\le L_i\le R_i\le n\)

题解

本题的状态比较显然。

由于每一层必然走过整条线段,所以显然从线段的左/右端点向下走是最优的。我们拆分子问题,求从 \((1,1)\) 走到第 \(i\) 层线段左/右端点的最少步数,可以通过从 \((1,1)\) 走到第 \(i-1\) 层线段左/右端点的最少步数求出,因此从 \((1,1)\) 走到第 \(i\) 层线段左/右端点的最少步数就是一个子问题。

根据我们得到的子问题,我们设状态 \(dp_{i,[0/1]}\) 表示从 \((1,1)\) 走到第 \(i\) 层线段的左/右端点的最少步数。以从 \(dp_{i-1,0}\)\(dp_{i,1}\) 转移为例(也就是从上一层线段左端点走到这一层线段右端点),我们首先需要横向走到这一层线段左端点,将横坐标从 \(L_{i-1}\) 走到 \(L_i\),显然需要 \(|L_{i-1}-L_i|\) 步,然后从线段左端点走到线段右端点,显然需要 \(R_i-L_i\) 步,又因为需要从上一层走到这一层,还需要额外的 \(1\) 步。我们得到转移 \(dp_{i,1}\gets dp_{i-1,0}+|L_{i-1}-L_i|+R_i-L_i+1\)。类似地,我们可以得到从 \(dp_{i-1,[0/1]}\)\(dp_{i,[0/1]}\) 的所有转移,对于一个目标状态,把所有能转移过来的结果取最小值即可。

最终我们还需要从 \(L_n\)\(R_n\) 走到 \((n,n)\),可以按照类似的方法求出 \(ans\gets\min\{dp_{n,0}+n-L_n,dp_{n,1}+n-R_n\}\)

初始状态就是从 \((1,1)\)\(R_1\) 的距离,或者到 \(R_1\) 再到 \(L_1\) 的距离。

参考代码

//By: Luogu@rui_er(122461)
#include <bits/stdc++.h>
#define rep(x,y,z) for(int x=y;x<=z;x++)
#define per(x,y,z) for(int x=y;x>=z;x--)
#define debug printf("Running %s on line %d...\n",__FUNCTION__,__LINE__)
using namespace std;
typedef long long ll;
const int N = 2e4+5; 

int n, L[N], R[N], dp[N][2];
template<typename T> void chkmin(T &x, T y) {if(x > y) x = y;}
template<typename T> void chkmax(T &x, T y) {if(x < y) x = y;}

int main() {
    scanf("%d", &n);
    rep(i, 1, n) scanf("%d%d", &L[i], &R[i]);
    dp[1][0] = 2 * R[1] - L[1] - 1;
    dp[1][1] = R[1] - 1;
    rep(i, 2, n) {
        dp[i][0] = min(dp[i-1][0]+abs(L[i-1]-R[i])+R[i]-L[i], 
                       dp[i-1][1]+abs(R[i-1]-R[i])+R[i]-L[i]) + 1;
        dp[i][1] = min(dp[i-1][0]+abs(L[i-1]-L[i])+R[i]-L[i], 
                       dp[i-1][1]+abs(R[i-1]-L[i])+R[i]-L[i]) + 1;
    }
    int ans = min(dp[n][0]+n-L[n], dp[n][1]+n-R[n]);
    printf("%d\n", ans);
    return 0;
}
posted @ 2021-07-14 19:25  rui_er  阅读(119)  评论(0)    收藏  举报