题目描述
贝茜有
C
(
1
≤
C
≤
1000
)
C(1\le C\le 1000)
C(1≤C≤1000) 门科目的作业要上交,之后她要去坐巴士和奶牛同学回家。
每门科目的老师所在的教室排列在一条长为
H
(
1
≤
H
≤
1000
)
H(1\le H\le 1000)
H(1≤H≤1000) 的走廊上,他们只在课后接收作业。交作业不需要时间.贝茜现在在位置
0
0
0,她会告诉你每个教室所在的位置,以及走廊出口的位置.她每走
1
1
1 个单位的路程,就要用
1
1
1 秒。她希望你计算最快多久以后她能交完作业并到达出口。
算法分析
先按位置从小到大排序,可以证明,没有提交的作业是一个连续的区间,不然先走到一个中间节点再前往那个边界节点再回来一定没有去往边界节点再回来优。怎么感觉证明这么牵强,像是骗人的
设 f [ i ] [ j ] [ 0 / 1 ] f[i][j][0/1] f[i][j][0/1] 表示区间 [ i , j ] [i,j] [i,j] 的作业没有提交,此时在 i / j i/j i/j 的最小时间,设计转移。
根据转移方程可知,下面代码的转移顺序是正确的。
代码实现
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#define UPD(x,y) x=std::min(x,y)
const int maxn=1005;
struct type {
int x,t;
bool operator < (const type &rhs) const {return x<rhs.x;}
} a[maxn];int f[maxn][maxn][2];
int main() {
int c,h,b;scanf("%d%d%d",&c,&h,&b);
for(int i=1;i<=c;++i) scanf("%d%d",&a[i].x,&a[i].t);
std::sort(a+1,a+1+c);
memset(f,0x7f,sizeof(f));
f[1][c][0]=std::max(a[1].x,a[1].t);f[1][c][1]=std::max(a[c].x,a[c].t);
for(int i=1;i<=c;++i) {
for(int j=c;j>=i;--j) {
UPD(f[i][j][0],std::max(f[i-1][j][0]+a[i].x-a[i-1].x,a[i].t));
UPD(f[i][j][0],std::max(f[i][j+1][1]+a[j+1].x-a[i].x,a[i].t));
UPD(f[i][j][1],std::max(f[i-1][j][0]+a[j].x-a[i-1].x,a[j].t));
UPD(f[i][j][1],std::max(f[i][j+1][1]+a[j+1].x-a[j].x,a[j].t));
}
}
int ans=0x7fffffff;
for(int i=1;i<=c;++i) UPD(ans,std::min(f[i][i][0],f[i][i][1])+abs(b-a[i].x));
printf("%d\n",ans);
return 0;
}