
题目传送门
题意:你必须经过每一行的几条线段,求从起点到终点的最短路思路:
DP!,首先,每一层的最优肯定是由上一层限制的最左端点或者最右端点下来将此行走完,那么可得转移方程:
1.f[i][0]表示走完第i行且停在第i行的左端点最少用的步数
2.f[i][1]表示走完第i行且停在第i行的右端点最少用的步数
那么转移:走完当前行,停到左端点,那么一定是从右端点过来的,那么从上一行左端点转移的话就是 f[i][0]=abs(上一行左端点的坐标-本行右端点的坐标+本行线段长度);停到右端点的方法可如法炮制。
最后就是炒鸡分类讨论
蜜汁代码(居然A了):
1 #include<bits/stdc++.h>
2 using namespace std;
3 const int maxn=2e4+9;
4 int l[maxn],r[maxn],dp[maxn][3];
5 int dist(int a,int b)
6 {
7 return abs(a-b);
8 }
9 int main()
10 {
11 ios::sync_with_stdio(0);
12 int n,t;
13 cin>>n;
14 for(int i=0;i<n;i++) cin>>l[i]>>r[i];
15 dp[0][1]=dist(1,r[0]);
16 dp[0][0]=dist(1,r[0])+dist(l[0],r[0]);
17 for(int i=1;i<n;i++)
18 {
19 for(int j=0;j<=1;j++)
20 {
21 int d1,d2;
22 if(j==0)
23 {
24 int x=l[i-1],y=r[i-1];
25 if(l[i-1]>=l[i]&&l[i-1]<=r[i]) d1=(2*dist(r[i],l[i-1])+dist(l[i-1],l[i]));
26 else if(l[i-1]>r[i]) d1=dist(l[i],r[i])+dist(r[i],l[i-1]);
27 else d1=dist(l[i],r[i])*2+dist(l[i-1],l[i]);
28 l[i-1]=r[i-1];
29 d2=d1;
30 if(l[i-1]>=l[i]&&l[i-1]<=r[i]) d1=(2*dist(r[i],l[i-1])+dist(l[i-1],l[i]));
31 else if(l[i-1]>r[i]) d1=dist(l[i],r[i])+dist(r[i],l[i-1]);
32 else d1=dist(l[i],r[i])*2+dist(l[i-1],l[i]);
33 l[i-1]=x;
34 r[i-1]=y;
35 if(d2+dp[i-1][0]<d1+dp[i-1][1]) dp[i][j]=dp[i-1][0]+d2;
36 else dp[i][j]=dp[i-1][1]+d1;
37 }
38 else
39 {
40 int x=l[i-1],y=r[i-1];
41 if(l[i-1]>=l[i]&&l[i-1]<=r[i]) d1=(2*dist(l[i],l[i-1])+dist(l[i-1],r[i]));
42 else if(l[i-1]<r[i]) d1=dist(l[i],r[i])+dist(l[i],l[i-1]);
43 else d1=dist(l[i],r[i])*2+dist(l[i-1],r[i]);
44 l[i-1]=r[i-1];
45 d2=d1;
46 if(l[i-1]>=l[i]&&l[i-1]<=r[i]) d1=(2*dist(l[i],l[i-1])+dist(l[i-1],r[i]));
47 else if(l[i-1]<r[i]) d1=dist(l[i],r[i])+dist(l[i],l[i-1]);
48 else d1=dist(l[i],r[i])*2+dist(l[i-1],r[i]);
49 if(d2+dp[i-1][0]<d1+dp[i-1][1]) dp[i][j]=dp[i-1][0]+d2;
50 else dp[i][j]=dp[i-1][1]+d1;
51 l[i-1]=x;
52 r[i-1]=y;
53 }
54 }
55 }
56 if(dp[n-1][0]+(n-l[n-1])>(n-r[n-1]+dp[n-1][1])) cout<<(n-r[n-1]+dp[n-1][1])+n-1<<endl;
57 else cout<<dp[n-1][0]+(n-l[n-1])+n-1<<endl;
58 return 0;
59 }