hnoi 2009 通往城堡之路

来源:互联网 发布:软件测试基本过程 编辑:程序博客网 时间:2024/04/30 12:46

这道题并不是我想出来的。。是看了网上一个程序然后自己yy出这个程序是干什么的。。

先放原地址:http://yuyuyusachs.blogbus.com/logs/61039360.html

这里再放我的代码,其实和他的差不多,只是这样方便看下文

然后大家看完了那篇文章之后如果没懂(反正我当时是没懂)可以看下面我写的。。

这个程序首先对于原来的序列求出一个解的下限,然后不断的调整,直到得出可行解,

首先,初始解是一个不断下降的序列,而且每次下降的幅度都取到极限(也就是题目中的d值)。

(注意,在初始解中,最后一个点的高度也是被改变了的。)那么,我们可以很容易的证明,对于一个可行解,每一个点的高度对于初始解都是不下降的,因为只有这样才能是它符合题意,同时我们需要把可行解的最后一项调整为原来的数才行。

首先,说明一下调整的规则。因为最终答案对于初始解一定是不下降的,所以我们的规则如果合理,可以使调整方向只向上不向下。

每次调整,我们都只从一个数开始到最后一个数都向上调同样的高度,因为这样可以保证我调整后使费用减小的前提下序列依然符合要求,即相邻两个数的差小于等于d。

接着解释一下s的作用。s表示的时从当前这个数到最后一个数中(当前解小于原数的个数)-(当前解大于原数的个数)。因为我们调整时是将这一段序列都往上调,所以一个数比原解小,则对于它的调整会使改变量减少,即费用降低;否则,会使改变量增大,即费用升高。

我们在调整过程中,必须时刻保证相邻的两数相差不大于d,所以要特别的处理一些情况(详见程序)。而且,在一次调整时,我们必须保证本来低于原数的当前解不能超过原数,因为若一次改变中解从低于原数变为了高于原数,那么它对于费用的改变量就不再是单调的了,所以我们每次的改变值不能超过min(原数-当前解)【注意,这里仅计算当前解小于原数的那些数】,然后,当我们把最后一个数的解调整成了当前解,那么就得出了答案。

现在,还存在一个问题,就是得出的答案是否一定为最优解。

那么,我们只需要要证明以下结论就可以了:

1.使序列中的一段区间上升,不会使费用更小;

2.使序列中的一段区间下降,不会使费用更小。

首先证明第一个结论:

对于一段区间,若它不上调只有两个可能:

1.这段区间内的s值不为正数,那么上调不会使解更优;

2.这段区间随一直到末尾的区间上调,但最后一个解已到达原数,不能再上调。那么,若是这一段区间继续上调,则会使此区间最后一个数与下一个数的差值大于d,因为在初始解中的差值是达到极限d的,切这段区间一直随末尾上调,那么它们直接的差并未减小,所以继续上调此区间必定会是差值增大,不符合条件。

综上所述,上调一段区间不会在符合题意的条件下使费用减小。

然后证第二个结论:

若可以使一个区间下调,那么它已经经过一段上调,因为初始解是保证不能下调的下限解。若这段区间下调,则可以看作原调整过程中的一个逆过程,那么使它下调不可能是费用减小,因为这不符合原算法的规则。所以,下调一段区间也不会在符合题意的条件下使费用减小。

证毕。

通过证明,我们可以知道,得到的解即为最优解,这个算法是正确的。

通过分析,每次调整会使最少一个数达到上界,所以算法复杂度不超过O(n^2)。

这个问题得到了解决(虽然其实不是我解决的)。