醉鬼同时移动问题的思路

今天有学生问了一个有趣的算法题目:

数轴上有n个位置不同的点,各点横坐标已知,分别代表n个醉鬼的位置,每个醉鬼可以向左或者向右水平移动s个距离(不允许原地不动),问所有的人都移动一次后,队伍的最短长度为多少(队伍的长度定义为最右边的人到最左边的人的距离).

在https://www.nowcoder.com/questionTerminal/ff0e55dcb75b45b09164c56f87cdf737中找到了同样的题目,

花了2个小时看明白了该文章里的思路,非常精巧,令人赞叹.现将细节整理出来,以备后来者参考.

1.问题等价于
先把整个队伍左移s个单位,那么现在每个人的合法操作就是原地不动(对应原问题中的左移s)或者向右移动2s(对应原问题的右移s操作).

2.现在问题转化成n个不同位置的人,v[i]为第i个人的坐标,每人可以原地不动或者向右移动m=2*s个单位,
求移动之后的队伍最小长度.为了讨论方便,我们假定第一个人的坐标为0.最后一个人的坐标为right

3.现在考虑新队伍的所有可能性
如果第2个人向右移动的话,则它右移动之后的新位置肯定不可能是新队伍的开头,
因为此时第1个人无论是否移动都必然还在第2个人的左边,
类似的第3个人到最后一个人都不可能经过右移成为新队伍的开头,
但是第一个人向右移动之后的位置有可能成为新队伍的开头
(相当于第1个人和第2人之间离的比较远,第一个人右移m之后仍然在第2个人的左边).
所以新队伍的开头只有可能是
第一个人右移之后的位置,或者第2个人到第n个人的原始位置.


4.下面的任务就是得到考虑候选解,
设第一个人的坐标为0,最后一个人的原始坐标为right.
(1)如果第1个人保持不动,则其他人也要原地不动才有可能得到最优解.即整个队伍的原始长度为一个候选解
(2)因为第一个人移动之后的坐标为m,则这个坐标也是所有新队列的左边界的上限.

依次检查第2到第n个点的原始位置是否可以成为新队列的起点,
检查的条件就是v[i]<= m,此时新队列的尾部坐标为end=max(right,v[i-1]+m), 这里要考虑到左边的人移动之后会越过原来的右边界的情形.

然后这个新对列的长度为end-v[i].

最后还要考虑第1个点移动m之后成为新的左边界的情况,此时的右边界就有可能是离m最近的前一个点平移之后的位置,

比如节点1移动m之后落到了原来的4和5之间,那么此时

节点2到4都要右移,队列的终点为end=max(right,v[4]+m).新队列长度为end-(v[1]+m)

5.从以上所有候选解中找出一个最小值即可.

你可能感兴趣的:(算法)