洛谷P3842 [TJOI2007]线段

本来想先写图论专题的,但这题蹦出来了,就先写她了啦啦啦啦~
题目链接https://www.luogu.org/problem/P3842(洛谷真是越改越丑了)

题目描述 在一个 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)。
输出格式 输出文件仅包含一个整数,你选择的最短路程的长度。
输入输出样例 输入
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 ≤ 20 000。

解题思路:第一眼看到这题,以为可以贪心搞(一个lc甚至现在还在这么想),但题中说线段必须全都走到,所以贪心不可行(甚至lc都已经发现了),而离开每一行时,最优情况一定是在左右端点,所以,考虑dp
f[i][0]表示第i行走完如果在左端点的最优质,f[i][1]表示在右端点最优。
本蒟蒻分了以下几种情况:
1在这里插入图片描述在这里插入图片描述
2

在这里插入图片描述
3
在这里插入图片描述分类讨论:
然后上代码

#include <cstdio>
#include <cstring>
#include <iostream>
#include <queue>
#include <algorithm>
using namespace std;
int n,hang,ans=0;
int l[20005];
int r[20005];
int f[29999][3];//F[X][0] left max 
int main(){
 scanf("%d",&n);
 for(int i=1;i<=n;i++) scanf("%d%d",&l[i],&r[i]);
 f[1][1]=r[1]-1;
 f[1][0]=r[1]-1+r[1]-l[1];
 for(int i=2;i<=n;i++){
   if(l[i-1]>=r[i]){
      f[i][1]=min(r[i]-l[i]+r[i]-l[i]+f[i-1][0]+1+l[i-1]-r[i],r[i]-l[i]+r[i]-l[i]+f[i-1][1]+1+r[i-1]-r[i]);
      f[i][0]=min(f[i-1][0]+1+l[i-1]-l[i],f[i-1][1]+1+r[i-1]-l[i]); 
      }
      else if(r[i-1]<=l[i]) {
       f[i][0]=min(r[i]-l[i]+r[i]-l[i]+f[i-1][1]+1+l[i]-r[i-1],r[i]-l[i]+r[i]-l[i]+f[i-1][0]+1+l[i]-l[i-1]);
       f[i][1]=min(f[i-1][1]+1+r[i]-r[i-1],f[i-1][0]+1+r[i]-l[i-1]);
   }
   else if(l[i]<=l[i-1]&&r[i]>=r[i-1]){
    f[i][0]=min(r[i]-l[i]+f[i-1][1]+1+r[i]-r[i-1],r[i]-l[i]+r[i]-l[i]+f[i-1][0]+1+l[i-1]-l[i]);
    f[i][1]=min(r[i]-l[i]+r[i]-l[i]+f[i-1][1]+1+r[i]-r[i-1],r[i]-l[i]+f[i-1][0]+1+l[i-1]-l[i]); 
   }
   else if(l[i]>=l[i-1]&&r[i]<=r[i-1]){
    f[i][0]=min(r[i]-l[i]+f[i-1][1]+1+r[i-1]-r[i],r[i]-l[i]+r[i]-l[i]+f[i-1][0]+1+l[i]-l[i-1]);
    f[i][1]=min(r[i]-l[i]+r[i]-l[i]+f[i-1][1]+1+r[i-1]-r[i],r[i]-l[i]+f[i-1][0]+1+l[i]-l[i-1]);
   }
   else if(l[i]>=l[i-1]&&l[i]<=r[i-1]){
    f[i][0]=min(r[i]-l[i]+f[i-1][1]+1+r[i]-r[i-1],r[i]-l[i]+r[i]-l[i]+f[i-1][0]+1+l[i]-l[i-1]);
    f[i][1]=min(r[i-1]-l[i]+r[i]-l[i]+f[i-1][1]+1,f[i-1][0]+1+r[i]-l[i-1]); 
   }
   else if(r[i]>=l[i-1]&&r[i]<=r[i-1]){
    f[i][1]=min(r[i]-l[i]+r[i]-l[i]+f[i-1][1]+1+r[i-1]-r[i],r[i]-l[i]+l[i-1]-l[i]+f[i-1][0]+1);
    f[i][0]=min(r[i]-l[i]+f[i-1][1]+1+r[i-1]-r[i],r[i]-l[i]+f[i-1][0]+1+r[i]-l[i-1]);
   } 
 }
 ans=min(f[n][0]+n-l[n],f[n][1]+n-r[n]);
 cout<<ans;
 return 0;
} 

ok 我要睡觉了zzz

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值