独木桥(青蛙过河)问题思考
题目描述
在河上有一座独木桥,一只青蛙想沿着独木桥从河的一侧跳到另一侧。在桥上有一些石子,青蛙很讨厌踩在这些石子上。由于桥的长度和青蛙一次跳过的距离都是正整数,我们可以把独木桥上青蛙可能到达的点看成数轴上的一串整点:0,1,……,L(其中L是桥的长度)。坐标为0的点表示桥的起点,坐标为L的点表示桥的终点。青蛙从桥的起点开始,不停的向终点方向跳跃。一次跳跃的距离是S到T之间的任意正整数(包括S,T)。当青蛙跳到或跳过坐标为L的点时,就算青蛙已经跳出了独木桥。
题目给出独木桥的长度L,青蛙跳跃的距离范围S,T,桥上石子的位置。你的任务是确定青蛙要想过河,最少需要踩到的石子数。
对于30%的数据,L?<=?10000;对于全部的数据,L?<=?10^9。<=?10^9<=?10^9<=?10^9<=?10^9<=?10^9<=?10^9=?10^9
输入
输入的第一行有一个正整数L(1?<=?l?<=?10^9),表示独木桥的长度。第二行有三个正整数S,T,M,分别表示青蛙一次跳跃的最小距离,最大距离,及桥上石子的个数,其中1?<=?s?<=?t?<=?10,1?<=?m?<=?100。第三行有M个不同的正整数分别表示这M个石子在数轴上的位置(数据保证桥的起点和终点处没有石子)。所有相邻的整数之间用一个空格隔开。<=?m?<=?100<=?m?<=?100<=?m?<=?100<=?m?<=?100<=?m?<=?100<=?m?<=?100=?M?<=?100
问题算法本身不难,一个从后往前反向求出起点最小石子个数的动态规划问题,搜索青蛙过河,网上可以找到很多帖子。不过只这么做是不够的,首先数据量大的时候,内存直接爆了,所以需要压缩数据,片段化处理;另一个就是一个特殊情况, 如果青蛙最小步数和最大步数相等时,直接计算 即可。
这里主要记录下我自己是怎么压缩的,思路主要是这样,首先对石子位置进行排序,然后从后往前遍历,如果发现两个石子之间距离过长,那么就以后一个石子为开头得到一个片段;然后计算经过这个片段的最小石子个数。最终整个独木桥的最小石子个数,就是所有片段结果之和。
那么现在的问题就是,怎么才算石子之间的距离足够长。如果前maxStep个数已经都一样了,那么再怎么往前推,都是一个数了;而多长的距离能够保证前面的数都变成最小值,我的想法比较简单粗暴,跟冒泡排序的想法有点接近,就是假设最后一个值(maxStep-1位置上的值)是最小值,那么它每一轮往前移动(maxStep-minStep)个位置,直接假定每一轮的长度为maxStep,所以它移动到第一个位置需要(maxStep - 1)*maxStep/(maxStep-minStep)。所以,如果两个石子之间的距离超过这个值,那么直接算出这个片段每个位置的最小石子数,然后取前面maxStep个值的最小值。
最后,如果到了最开始的片段,如果第一个石子离起点还是足够远,可以一样计算,但是,如果第一个石子离起点很近的时候,直接计算到起点的最小石子数即可。