写这篇博文的原因是因为这个星期遇到了两次这种问题(什么样的排序问题下文马上就说),一开始对题解用到的化简非常的不明白,所幸jxt又教了我为什么,所以自己在这里记下来,以备忘QAQ
问题描述
刘汝佳的《算法竞赛入门经典训练指南》(白书)2012版的第2页说到了UVa 11729,题目大意就是有n个任务,布置任务的时间为 Bi ,部下去执行任务的时间是 Ji ,问如何安排布置任务的次序使所有任务尽早执行完成(即最后一个执行完的任务应尽早结束)。
看到这题,相信我们可以达成这样的共识:我们需要先给所有任务排序(确定执行任务的步骤),然后开始模拟任务的布置流程,确定答案。
如何给任务排序呢?我的思路是:一个任务i可以排在任务j前面的条件是,先布置这个任务两个任务完成的时间要小于后布置这个任务两个任务完成的时间。即:
struct Jobs {
int j, b;
bool operator<(const Jobs &x) const {
return max(b + j, b + x.b + x.j) < max(x.b + x.j, b + x.b + j);
}
};
感觉很正确,并且这份代码ac了
但是白书上的代码是另外一种写法:
struct Jobs {
int j, b;
bool operator<(const Jobs &x) const {
return j > x.j;
}
};
一开始,sjt说我的代码存在问题,因为我这个大小判定式不一定有传递性(当然现在我知道了证明方法),如果没有传递性的话,至少 O(nlogn) 的排序算法不一定可以正确地区分出各个元素的大小关系(事实上没有传递性就无法排序把?)。后来他通过分类讨论证明了这两个式子是等价的。既然等价,下式具有传递性,那么上式也具有传递性。
可如何从上式推出下式呢?白书第4页通过讨论不同情况说明了下式的正确性。但遇到其他一些问题,我们也要通过不同的情况讨论,分析出下式吗?
由上式推出下式的一般方法
%%%jxt
原式: