P3842 [TJOI2007] 线段(动态规划)
题目描述
在一个 n×n 的平面上,在每一行中有一条线段,第 i 行的线段的左端点是 (i,Li),右端点是 (i,Ri)。
你从 (1,1) 点出发,要求沿途走过所有的线段,最终到达 (n,n) 点,且所走的路程长度要尽量短。
更具体一些说,你在任何时候只能选择向下走一步(行数增加 1)、向左走一步(列数减少 1)或是向右走一步(列数增加 1)。当然,由于你不能向上行走,因此在从任何一行向下走到另一行的时候,你必须保证已经走完本行的那条线段。
输入格式
第一行有一个整数 n。
以下 n 行,在第 i 行(总第 (i+1) 行)的两个整数表示 Li 和 Ri。
输出格式
仅包含一个整数,你选择的最短路程的长度。
输入输出样例
输入 #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% 的数据,1≤n≤2×104,1≤Li≤Ri≤n。
思考:
我们首先对于第一行来说,如果走完当前线段,那么要么停留在左端点,要么停留在右端点。对于下一行,我们任然要走完线段,此时若停留在右端点,则会产生两种情况:从上一行的左端点下来,走完当前线段,停留在右端点;从上一行的右端点下来,走完当前线段,停留在左端点。若停留在左端点,则也具有上述相似的两种情况。由于我们需要求最后到达(n,n)的最小距离,所以我们需要最小化每一行走完线段的最小距离。
我们定义dp[i][0]为在当前i行,走完线段后,停留在左端点的最小距离;dp[i][1]为在当前i行,走完线段后,停留在左=右端点的最小距离。
#include<bits/stdc++.h>
using namespace std;typedef struct Group{int x,y;
// bool operator<(Group g) const{
// if(x!=g.x) return x<g.x;
// else return y<g.y;
// }
}G;
typedef long long ll;
const int mod = 1e6+7;
int n,m;
int r,c;
int dx[4] = {0,0,1,-1};
int dy[4] = {1,-1,0,0};int main(){ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);cin>>n;vector<int> L(n+1);vector<int> R(n+1);for(int i=1; i<=n; i++){int l,r;cin>>l>>r;L[i] = l;R[i] = r;}vector<vector<int>> dp(n+1, vector<int>(2,0));dp[1][0] = abs(R[1]-1) + R[1]-L[1];dp[1][1] = abs(L[1]-1) + R[1]-L[1];for(int i=2; i<=n; i++){int L_r = 1 + abs(R[i]-L[i-1]) + dp[i-1][0];int L_l = 1 + abs(L[i]-L[i-1]) + dp[i-1][0];int R_r = 1 + abs(R[i]-R[i-1]) + dp[i-1][1];int R_l = 1 + abs(L[i]-R[i-1]) + dp[i-1][1];dp[i][0] = min(L_r,R_r)+R[i]-L[i];dp[i][1] = min(L_l,R_l)+R[i]-L[i];}cout<<min(dp[n][0]+abs(L[n]-n),dp[n][1]+abs(R[n]-n))<<endl;return 0;
}