运用NP求解 “跳跃游戏”---计蒜客

计蒜客里面有一道“跳跃游戏的问题”

给定一个非负整数数组,假定你的初始位置为数组第一个下标。

数组中的每个元素代表你在那个位置能够跳跃的最大长度。

你的目标是到达最后一个下标,并且使用最少的跳跃次数。

例如:

A = [2,3,1,1,4],到达最后一个下标的最少跳跃次数为 2。(先跳跃 1 步,从下标 0 到 1,然后跳跃 3 步,到达最后一个下标。一共两次)

输入格式

第一行输入一个正整数 n,接下来的一行,输入 n 个整数,表示数组 A。

输出格式

最后输出最少的跳跃次数。

这道题目吧,其实理解了动态规划算法的思路也就不是那么困难了。而大家都知道,动态规划问题就是说将大问题细化成小问题,而小问题的结果已经在之前的递归中被保存到数组里,也就是说大问题的求解可以直接拿小问题的结果来用。

对于这个跳跃问题,我们可以将思想分为三个部分。

第一:

int num ;
    cin>>num;
    int intt[101];
    intt[0]=-1;
    for(int i=1;i<=num;i++){
        cin>>intt[i];
        array[i] = 99999;
    }

在这部分代码中,我们是定义了一个intt[]数组来保存输入的num个数,并且array[i]的作用就是用来保存跳到intt[i] 这个数的最优解。在开始的时候,我们复制给array[i]一个很大的数(给定一个大的初值,之后如果有小的数就直接覆盖掉)。

之后就是算法的思想所在:

array[1] = 0;
    for(int j =1;j<=num;j++){
        for (int n =1;n<=intt[j]&&n+j<=num;n++){
            array[n+j] =  min(array[n+j],array[j]+1);
        }
    }

在这部分代码中,我们给array[1]赋值为0是因为第一个数本来就不用跳跃,所以理所当然是0。在循环结构中,我们需要做num次循环(num是我们输入的数的个数,因为程序中array也就需要num个值,所以num次循环足够了)。我定义的变量均是从1开始,这样方便我们理解。当j为1的时候,也就意味着我们此时得到了第一个数的值(例如我们的例子中的第一个数为“2”,所以我n的循环次数就是从1到2共两次。换句话说就是我的第一个数的领域就是2),而需要加结束循环的条件(条件为n<=intt[j],n+j<=num这个条件意思是——例:当我的j为1的时候,我的n若可以等于4,也就是说我的第一个数的领域可以到达最后一个数,所以意味着我第一步就可以达到题目要求,所以就直接跳出来了,不需要循环)。

之后array[n+j] =  min(array[n+j],array[j]+1)方程才是NP的关键,这个方程动态更新最小值。倘若n+j这个位置是第一次赋值,那么就意味着是99999与array[j]+1比较,看谁最小(肯定是后者最小的。。)

还有可能是array[n+j]已经被赋值过了(若这个位置可以被好多个领域覆盖到,就有可能array[n+j]不等于999999),这个时候就把最小的赋值过去就好。递归5次后就得到了所以位置的最优解。

之后:

cout<<array[num]<<endl;

输出最后一个位置的最优解就好。

PS:这个平台上还有一道题目是判读是否为true或false,也就是在这个程序的基础上加一句判读最后一个array[num]是否为99999,如果是证明是false,不是就为true。是不是很基础呀~~~~~~~~~~~~~~~~~~~~~~~~~~~~

要学习的还很多,还要继续努力。。。。。。。  

————————————————————Made By Pinging~!

原文地址:https://www.cnblogs.com/Pinging/p/7719864.html