首页 > 试题广场 >

袋鼠过河

[编程题]袋鼠过河
  • 热度指数:33794 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 32M,其他语言64M
  • 算法知识视频讲解
一只袋鼠要从河这边跳到河对岸,河很宽,但是河中间打了很多桩子,每隔一米就有一个,每个桩子上都有一个弹簧,袋鼠跳到弹簧上就可以跳的更远。每个弹簧力量不同,用一个数字代表它的力量,如果弹簧力量为5,就代表袋鼠下一跳最多能够跳5米,如果为0,就会陷进去无法继续跳跃。河流一共N米宽,袋鼠初始位置就在第一个弹簧上面,要跳到最后一个弹簧之后就算过河了,给定每个弹簧的力量,求袋鼠最少需要多少跳能够到达对岸。如果无法到达输出-1

输入描述:
输入分两行,第一行是数组长度N (1 ≤ N ≤ 10000),第二行是每一项的值,用空格分隔。


输出描述:
输出最少的跳数,无法到达输出-1
示例1

输入

5
2 0 1 1 1

输出

4
逻辑清晰
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.util.Scanner; /**  * @author: noob  * @description :  * @Date : 22:41 2024/10/29  */ // https://www.nowcoder.com/practice/74acf832651e45bd9e059c59bc6e1cbf?tpId=182&tqId=34693&ru=/exam/oj public class 袋鼠过河 { // 一开始使用的bfs 发现超时过不了;  // 然后用贪心 每一步都使用利益最大化  public static void main(String[] args) throws IOException { Scanner scanner = new Scanner(System.in); int n = scanner.nextInt(); int[] arr = new int[n]; for (int i = 0; i < n; i++) { arr[i] = scanner.nextInt();
        } int count = 0; for (int curIndex = 0; curIndex < n; ) { // 如果为0 则跳不出去失败  if (arr[curIndex] == 0) { count = -1; break;
            } // 如果本次最大跳跃 直接跳出去了成功,并且跳跃=1  if (curIndex + arr[curIndex] > n - 1) { count++; break;
            } // 下面寻找 本次跳跃后 可以达到最大的位置  int whichIndex = 0; int maxlength = 0; int can = arr[curIndex]; for (int i = can; i > 0; i--) { if (curIndex + i + arr[curIndex + i] > maxlength) { whichIndex = curIndex + i; maxlength = curIndex + i + arr[curIndex + i];
                }
            } // 选择完成  跳下一步  count++; // 更新当前位置  curIndex = whichIndex;
        } System.out.println(count);
    }
}


}
发表于 2024-10-29 23:57:40 回复(0)
import java.util.Scanner;
public class Main {
static int max = Integer.MIN_VALUE;
public static void main(String[] args) {
// 使用动态的规划进行查看
Scanner sc = new Scanner(System.in);
int n =sc.nextInt();
int[] arr = new int[n];
for (int i = 0; i < arr.length; i++) {
arr[i] = sc.nextInt();
}
System.out.println(dp(arr));
}
private static int dp(int[] arr) {
    // 创建一个dp数组用来记录每一个位置的最小步数
    int[] dp = new int[arr.length];
    for (int i = 0; i < arr.length; i++) {
        dp[i] = Integer.MAX_VALUE;
    }
    dp[0] = 0;
    int n = arr.length;
    // 设计每每一个位置跳到的最小步数
    for (int i = 0; i < arr.length; i++) {
  // 如果出现 3 0 0 0 0 5 0 0 0 0 的情况就要排除,所以当前的dp[i]必须不等于最大值
        if(dp[i] != Integer.MAX_VALUE)for (int j = 0; j <= arr[i]; j++) {
            if (i + j <= arr.length - 1) {
                dp[i + j] = Math.min(dp[i + j], dp[i] + 1);
            } if (i + j > arr.length - 1) { // 如果当前的 加上可以向前跳的距离大于 河的长度直接返回 dp[i] + 1
                return dp[i] + 1;
            }
        }
    } // 最后进行判断,只要最后一个位置是的不等于int最大值并且arr[arr.length - 1] > 0 就返回dp[n - 1] + 1
    if (dp[n - 1] > 0 && arr[n - 1] != 0) {
        return dp[n - 1] + 1;
    } else {
        return -1;
    }
}

}

编辑于 2019-03-03 20:11:01 回复(0)

解:思路

当前跳板序号

当前跳板弹跳值

判断是否可以到对岸

是则到岸

否则判断跳到下个跳板后是否有机会过河(即前面力所能及的跳板弹跳值是否为全零)

是则输出-1

否则判断跳到哪个板及其该板弹跳值加和最大,跳到加和最大的板上(此处小循环)

发表于 2018-12-28 21:23:43 回复(0)
//保证每一跳所获得的下一跳范围最大
//同时下一跳一定要跳出当前范围 否则无法跳到河对岸
import java.util.*;
public class Main{
     public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int len = in.nextInt();
        int times=0;
        int max=0;
        int maxIndex=0;
        int[] step = new int[len];
        while(in.hasNext()){
            for(int i=0;i<len;i++){
                step[i]=in.nextInt();
            }
        }
        for(int i =0;i<len;){
            max=step[i]+i;
            if(max>=len){
                times++;
                System.out.println(times);
                break;
            }
            for(int j=1;j<=step[i];j++){
                if(step[i+j]+(i+j)>max){
                    max=step[i+j]+i+j;
                    maxIndex=j;
                }
            }
            if(max==step[i]+i){
                System.out.println(-1);
                break;
            }
            else{
                times++;
                i+=maxIndex;
            }
        }
    }
}
发表于 2018-11-17 16:34:42 回复(0)
首先说一下,这道题是很经典的dp. 类似于走矩阵等问题
很显然本题不能用Greedy Algorithm做,因为有的时候,为了取到临时的最大值,可能会失去以后的更大值

import java.util.*;


public class Main{

    public static void main(String args[]){

        Scanner sc = new Scanner(System.in);

        int arrLen = sc.nextInt();

        int[] arr = new int[arrLen];

        int[] dp = new int[arrLen];

        int minNum = Integer.MAX_VALUE;

        dp[0]=0;

        for(int i=1; i<dp.length; i++){

            dp[i] = Integer.MAX_VALUE;

        }
       /*我们要的是最小的value,所以把array里面所有的东西都设置成最大值,这样只要有修改,就会更新array里的值*/

        for(int i=0; i<arrLen; i++){

            arr[i] = sc.nextInt();

        }

        if(arr[0]==0){

            System.out.println(-1);

            return;

        }

 //如果第一个就是0直接-1
//下面是用的top-bottom 的方法
//当我每走一格的时候,我都会判断,到达下面所有可到达的格子的最小步数是多少
//如果我们可走的步数超出了河的长度,那我们就和目前最小的那个总步数进行比较
        for(int i=0; i<arr.length; i++){

            if(arr[i]!=0){

                for(int j=i+1; j<=Math.min(arr.length-1 , i+arr[i]); j++){

                    dp[j] = Math.min(dp[i]+1, dp[j]);

                }

                if(i+arr[i]>=dp.length){

                    minNum = Math.min(minNum, dp[i]+1);

                }

            }

        }

//判断无法通过的情况很简单
/*当整个dp的array都走一遍,如果发现有某个值是Integer.MAX_VALUE,证明无法到达此位置,直接print -1 并且结束掉当前程序*/
        for(int i=1; i<dp.length; i++){

            if(dp[i]==Integer.MAX_VALUE){

                System.out.println(-1);

                return;

            }

        }
//如果没有到不了的点直接print 结果

        System.out.println(minNum);

    }

}



发表于 2018-11-16 13:18:59 回复(0)

import java.io.BufferedReader;
import java.io.InputStreamReader;

public class Main {

    public static void main(String[] args) throws Exception{
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); 
        String str = br.readLine(); 
        int num = Integer.parseInt(str);;
        str = br.readLine(); 
        int[] arr; 
        String[] str1=str.split(" ");
        arr=new int[str1.length];
        int i=0;
        for(String a:str1){
            for(int j=0;j<a.length();j++)
               arr[i]=arr[i]*10+a.charAt(j)-'0';
            i+=1;
        }
        int step=0;
        int index,value;
        int max_step;
        int tmp;
        for(i=0;;){
            step++;
            index=1;
            value=-1;
            max_step=arr[i];
            if(max_step==0){
                step=-1;
                System.out.println(step);
                break;
            }
            else{
                if((i+max_step)>=num){
                    System.out.println(step);
                    break;
                } 
                for(int j=0;j<max_step;j++){
                    tmp=arr[i+j+1]+j+1;
                    if(tmp>=value){
                        index=j+1;
                        value=tmp;
                        }
                }
            }
            i+=index;
        }
         
    }
}
发表于 2018-10-08 20:23:40 回复(0)
import java.util.Arrays;
import java.util.Scanner;

public class 袋鼠过河 {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Scanner in = new Scanner(System.in);
        int n = in.nextInt();
        int[] power = new int[n];
        for (int i = 0; i < n; i++) {
            power[i] = in.nextInt();
        }
        System.out.println(jump(n, power));
    }
    
    public static int jump(int n, int[] power)
    {
        //动态规划问题
        int[] res = new int[n + 1];//存储到某一位置的最少步数,加一位置表示岸边
        res[0] = 0;
        for (int k = 1; k <= n; k++) {
            //存储最少步数 ,可变
            int tmp = Integer.MAX_VALUE;
            for (int i = 0; i < k; i++) {
                //说明能从i位置跳到k位置,且最小
                if (i + power[i] >= k && res[i] + 1 < tmp) {
                    //k位置的步数等于从跳到i位置的步数加一
                    res[k] = res[i] + 1;
                    tmp = res[k];
                }
            }
        }
        //当中有一个为0说明无法到岸边
        for (int i = 1; i <= n; i++) {
            if (res[i] == 0) {
                res[n] = -1;
            }
        }
        //n位置表示到岸边的步数
        return res[n];
    }

}

发表于 2018-09-16 17:22:54 回复(0)
         这一题是比较基础的动态规划的题目,关键是要找出在每一个河桩上,袋鼠需要的最少跳跃次数;然后寻找进入下一个河桩,跳跃数是如何变化的,总之,就是寻找状态以及状态转移。
就这一题来说,下一个河桩的最少跳跃次数就是之前河桩最少的跳跃次数加一。我的程序时间复杂度是O(N^2),是我感觉应该可以提高到O(nlogn).奈何弱鸡一枚,心有戚戚焉。。。
发表于 2018-09-09 14:50:18 回复(0)
/**
 * 贪心
 */
import java.util.Scanner;
public class Main {
    public static void main(String[] args) {
        Scanner sc= new Scanner(System.in);
        int n=sc.nextInt();
        int[] a=new int[n];
        for (int i = 0; i < a.length; i++)
            a[i]=i+sc.nextInt();    //i位置最远能到达的位置

        int step=1;
        int cur_max_i=a[0];//当前能到达的最远位置
        int max_i=a[0];//遍历过程中能到达的最远位置
        for (int i = 1; i < a.length; i++) {
            if (cur_max_i<i) {
                step++;
                //遍历过程中不能跳到比当前更远的位置了
                if (cur_max_i==max_i) {
                    System.out.println(-1);
                    break;
                }
                cur_max_i=max_i;
            }
            if (max_i<a[i]) {
                max_i=a[i];
            }
            //当前遍历过程中已经有能到达河对岸的位置了
            if (max_i>=a.length) {
                System.out.println(step+1);
                break;
            }
        }
        sc.close();
    }
}
发表于 2018-09-01 22:34:12 回复(0)
使用图论来解决
首先,要知道袋鼠只能往前跳,往前跳几步是本题目的关键,看到好多人用动态规划做的,下面我用另一种图论方法来解决。
其实,每一个桩子都可以视作一个图的结点,而弹簧能跳到某个桩子,那么与桩子的距离为1(图论叫可达),跳不到距离就是0,因此可以建立a[][],a[i][j]表示第i个桩子能否跳到第j个桩子,每次输入一个桩子的值,就把它之后的 k个桩子的a[i][i+k]置为1,然后有向图就产生了。

问题就便变成了,求从起点0到N点的最短路径。  方法有很多,我这里采用简化的Dijsktra 算法,因为不存在往回跳,所以就一直从头选取点,然后判断与剩下的节点的距离,算法思想没变,只是省去了每次寻找最小值的过程而直接换成了最左边的没被选择的点。
a[9][n]就是最后的结果,如果还是最初的最大值(Java里面是Integer,MAX_VALUE),那就是不可达,输出-1

时间整体复杂度  在Dijsktra 算法种,核心代码执行 : 1+2+3+...+n=O(n2)  ,不是很高也不是很低.。n=10000还可以接收,最终代码AC了,下面贴出代码,欢迎大家指教。
package TestMain;

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner aa=new Scanner(System.in);
        int n=aa.nextInt();
        int a[][]=new int[n+1][n+1];
        for(int i=0;i<=n;i++){
            for(int j=0;j<=n;j++){
                a[i][j]=Integer.MAX_VALUE;
            }
        }
        for(int i=0;i<n;i++){
            int index=aa.nextInt();
            for(int j=1;j<=index&&i+j<=n;j++){
                a[i][i+j]=1;
            }
        }
        int dis[]=new int[n+1];
        int mind=0,min=Integer.MAX_VALUE;
        for(int i=1;i<=n;i++){
            for(int j=i+1;j<=n;j++){
                if(a[0][i]!=Integer.MAX_VALUE&&a[i][j]!=Integer.MAX_VALUE)
                    a[0][j]=Math.min(a[0][j], a[0][i]+a[i][j]);
            }
        }
        if(a[0][n]==Integer.MAX_VALUE)
            System.out.println("-1");
        else  System.out.println(a[0][n]);
        
        
    }
}


发表于 2018-08-17 16:28:57 回复(0)
import java.util.Scanner;
public class Main {
    public static void main(String[] args){
        Scanner input = new Scanner(System.in);
        int n = input.nextInt();
        int[] arrays = new int[n];
        for(int i = 0; i < n; i++){
            arrays[i] = input.nextInt();
        }
        //jumpLength:袋鼠跳了多少米
        //cur: 当前在哪一个弹簧
        //count: 跳了多少次
        int jumpLength = 0;
        int cur = 0;
        int count = 0;

        while(jumpLength <n){
            //当前弹簧的弹力为0时失败
            if(arrays[cur] != 0){
                //whichone: 下一跳能跳到的最佳弹簧(离出发地的距离+弹簧弹力 最大)
                //初始whichone在下一个弹簧处
                int whichone = cur + 1;
                //如果已经跳的距离加上当前弹簧的弹力能够过河的话,结束
                if(jumpLength+ arrays[whichone - 1]  >= n){
                    count++;
                    break;
                }
                //选择whichone
                for(int j = cur + 1; j < cur + arrays[cur]; j++){
                    if((arrays[whichone] + whichone) <= (arrays[j+1] + j+1)){
                        whichone = j + 1;
                    }
                }
                //跳到下一个弹簧
                jumpLength += whichone - cur;
                cur = whichone;
                count++;
            } else{
                count = -1;
                break;
            }
        }
        System.out.println(count);
    }
}
发表于 2018-05-11 14:58:01 回复(0)
package bisheng.dongtaiguihua;

import java.util.Scanner;

public class daishuguohe {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int N = sc.nextInt();
        int[] arr = new int[N];
        for (int i = 0; i < N; i++) {
            arr[i] = sc.nextInt();
        }
        // 记录步数
        int count = 0;
        int j = N;
        while (j > 0) {
            for (int i = 0; i < j; i++) {
                if (i == j - 1) {
                    if (arr[j - 1] == 0) {
                        System.out.println(-1);
                        j = -1;
                        break;
                    }
                }
                if (j - i <= arr[i] && arr[i] != 0) {
                    count++;
                    j = i;
                    break;
                }
            }

        }
        if (j != -1) {
            System.out.println(count);
        }
    }
}

发表于 2018-05-01 20:32:37 回复(0)
import java.util.*;
public class Main {
    public static void main(String[] args)
    {
         Scanner in=new Scanner(System.in);
         while (in.hasNext())
         {
             int n=in.nextInt();
             int[] zhuangzi=new int[n];
             for(int i=0;i<n;++i)
                 zhuangzi[i]=in.nextInt();
             System.out.println(DynamicProgram(zhuangzi));
         }
    }
    
   public static int DynamicProgram(int[] dx)
   {
       int i,j,len=dx.length;
       int[] dp=new int[len+1];
       for(i=0;i<=len;++i)
           dp[i]=Integer.MAX_VALUE;
       dp[0]=0;
       if(dx[0]==0) return -1;
       for(i=0;i<len;++i) {
           if(dx[i]!=0)
           for (j = 1; j <= dx[i]; ++j)
           {
               if((i+j)<len&&dx[i+j]!=0&&dp[i]!=Integer.MAX_VALUE)
                   dp[i+j] = Math.min(dp[i+j],dp[i]+1);
               else if(i+j>=len&&dp[i]!=Integer.MAX_VALUE)
                   dp[len]=Math.min(dp[len],dp[i]+1);
           }

       }
       if(dp[len]==Integer.MAX_VALUE)
           return -1;
       else 
           return dp[len];
   }
}

发表于 2018-01-06 17:37:05 回复(0)
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        while (sc.hasNext()) {
            int n = sc.nextInt();
            int[] arr = new int[n];
            for (int i = 0; i < arr.length; i ++) {
                arr[i] = sc.nextInt();
            }
            int[] dp = new int[n + 1];
            for (int i = 0; i < n; i ++) {
                int endPosition = Math.min(i + arr[i], n);
                for (int j = i + 1; j <= endPosition; j ++) {
                    if(dp[j] == 0) dp[j] = dp[i] + 1;
                }
                if(dp[n] != 0 || (arr[i] == 0 && dp[i] == 0)) break;
            }
            if(dp[n] != 0) System.out.println(dp[n]);
            else System.out.println( - 1);
        }
    }
}

发表于 2017-11-28 00:45:03 回复(0)
import java.util.*;

public class Main {
    private static Scanner scanner = new Scanner(System.in);
    private static int[] powers;
    private static int[] steps;

    public static void main(String[] args) {
        powers = new int[scanner.nextInt()];
        for(int i = 0; i < powers.length; i++)
            powers[i] = scanner.nextInt();
        steps = new int[powers.length + 1];
        
        //选择正向方式或逆向方式执行皆可,只选一种。
        System.out.println(getMinStep(powers.length));  //逆向
        //setMinSteps();                                                       正向
        //System.out.println(steps[powers.length]);
    }
    /**
    *    动态规划-逆向推导
    */
    private static int getMinStep(int n) {
        if (n == 0 || steps[n] != 0)
            return steps[n];
        int min = -1;
        for (int i = n - 1; i >= 0; i--)
            if (powers[i] >= n - i) {
                int step = getMinStep(i);
                if (step != -1)
                    min = min == -1 ? (step + 1) : Math.min(min, step + 1);
            }
        steps[n] = min;
        return min;
    }
    /**
    *    动态规划-逆向推导
    */
    private static void setMinSteps(){
        for(int i = 1; i < steps.length; i++){
            steps[i] = -1;
            for(int j = i - 1; j >= 0; j--)
                if(steps[j] != -1 && powers[j] >= i - j)
                    steps[i] = steps[i] == -1 ? (steps[j] + 1) : Math.min(steps[j] + 1, steps[i]);
        }
    }
}
发表于 2017-09-16 15:51:41 回复(0)

动态规划问题:

  • 先将处在各个桩上时,能够跳跃的最大距离存储在数组 arrA 中。并且设置数组 arrB 存储到达此点时,需要最少需要跳跃的次数,初始化为Int型数组的最大值。 初始化 arrB[0] = 0,因为一开始就处在第一个桩上,不用跳跃。
    result 储存结果。
  • 然后i从 0 开始遍历完数组 arrB,j 从 1 开始到arrA[i] 更新数组arrB[i+j]的值并且更新数组 arrB[i + j],状态转移方程为

    arrB[i + j] = Math.min(arrB[i + j], arrB[i] + 1)

  • 一旦确定了 i + j >= n 也就是跳到对岸时,得用result 和 arrB[i] + 1 比较,result并且取最小值。
  • 得注意的是,可能遍历的 arrB[i] 存储的值为 Integer.MAX_VALUE,也就是之前的桩子不能跳跃到这条桩子上的,得用contine语句将后面语句结束掉,重新开始 i + 1 时的循环。
import java.util.Scanner; public class Main{ public static void main(String args[]){
        Scanner scanner = new Scanner(System.in); int n = scanner.nextInt(); int arrA[] = new int[n]; int arrB[] = new int[n]; for(int i = 0; i < n; i ++){
            arrA[i] = scanner.nextInt();
            arrB[i] = Integer.MAX_VALUE;
        }

        arrB[0] = 0; int result = Integer.MAX_VALUE; for(int i = 0; i < n; i++){ if(arrB[i] == Integer.MAX_VALUE) continue; for(int j = 1; j <= arrA[i]; j++){ if(i + j >= n){
                    result = Math.min(arrB[i] + 1, result); break;
                }
                arrB[i + j] = Math.min(arrB[i + j], arrB[i] + 1);
            }
        } if(result == Integer.MAX_VALUE)
            result = -1;


        System.out.println(result);

    }
}
编辑于 2017-08-31 16:15:10 回复(0)
还是可以On的
import java.util.*;

public class Main {
	
    public static void main(String[] args) {
    	Scanner sc = new Scanner(System.in);
    	int n;
    	int[] arr;
    	while(sc.hasNext()) {
    		n = sc.nextInt();
    		arr = new int[n];
    		for(int i = 0; i < n; i++) {
    			arr[i] = sc.nextInt();
    		}
    		int step = 0;
    		int cur = 0;
    		int next = 0;
    		for(int i = 0; i < n; i++) {
    			if(i > cur) {
    				if(next == 0) {
    					break;
    				}
    				cur = next;
    				next = 0;
    				step++;
    			}
    			next = Math.max(next, arr[i] == 0 ? 0 : arr[i] + i);
    			if(next >= n) {
    				break;
    			}
    		}
    		if(next == 0)
    			System.out.println(-1);
    		else
    			System.out.println(step + 1);
    	}
    }
}



编辑于 2017-08-28 21:03:54 回复(0)
import java.util.*;
public class Main {
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		int N = sc.nextInt();
		int[] num = new int[N + 1];
		for (int i = 0; i < N; i++) num[i] = sc.nextInt();
		num[N] = 1;//这是在陆地上了,不为0就可以了
		int[] dp = new int[N + 1];
		for (int i = 0; i <= N; i++) dp[i] = 10000;
		
		dp[0] = 0;
		for (int j = 1; j <= N; j++){
			if (num[j] == 0) continue;
			for (int i = 0; i < j; i++){
				if (num[i] >= j - i) dp[j] = Math.min(dp[i] + 1, dp[j]);
			}
		}
		
		System.out.println((dp[N] == 10000) ? -1 : dp[N]);//跳到陆地上最少需要的step

	}

}

编辑于 2017-08-20 11:01:38 回复(0)

import java.util.Scanner;

public class Main {

public static void main(String[] args) {
try (Scanner scanner = new Scanner(System.in)) {
A: while (scanner.hasNext()) {
int n = scanner.nextInt();
int[] z = new int[n];
for (int i = 0; i < n; i++) {
z[i] = scanner.nextInt();
}
int t = 0, now = 0;
while (now < n) {
if (z[now] == 0) {
System.out.println(-1);
continue A;
}
if (z[now] == 1) {
now++;
t++;
continue;
}
int max = 0, next = 0;
for (int i = 1; i <= z[now]; i++) {
if (now + i >= n) {
System.out.println(++t);
continue A;
}
int m = z[now + i] - (z[now] - i);
if (m >= max) {
max = m;
next = now + i;
}
}
now = next;
t++;
}
System.out.println(t);
}
}
}

}
考虑边界
发表于 2017-08-14 20:08:17 回复(0)