【USACO Open04】交作业

题目描述

贝茜有 C ( 1 ≤ C ≤ 1000 ) C(1\le C\le 1000) C(1C1000) 门科目的作业要上交,之后她要去坐巴士和奶牛同学回家。
每门科目的老师所在的教室排列在一条长为 H ( 1 ≤ H ≤ 1000 ) H(1\le H\le 1000) H(1H1000) 的走廊上,他们只在课后接收作业。交作业不需要时间.贝茜现在在位置 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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值