zoukankan      html  css  js  c++  java
  • 一个算法题,又是小明。囧

      第一次写博客文章,有点小紧张。若是有什么错误还望众大神指点。为了备战下个月的蓝桥杯,苦战算法题,觉得有一道题不错,就拿来分享一下。

    原文如下:地宫取宝X 国王有一个地宫宝库。是 n x m 个格子的矩阵。每个格子放一件宝贝。每个宝贝贴着价值标签。地宫的入口在左上角,出口在右下角。小明被带到地宫的入口,国王要求他只能向右或向下行走。走过某个格子时,如果那个格子中的宝贝价值比小明手中任意宝贝价值都大,小明就可以拿起它(当然,也可以不拿)。当小明走到出口时,如果他手中的宝贝恰好是k件,则这些宝贝就可以送给小明。

    请你帮小明算一算,在给定的局面下,他有多少种不同的行动方案能获得这k件宝贝。
    【数据格式】输入一行3个整数,用空格分开:n m k (1<=n,m<=50, 1<=k<=12)接下来有 n 行数据,每行有 m 个整数 Ci (0<=Ci<=12)代表这个格子上的宝物的价值,要求输出一个整数,表示正好取k个宝贝的行动方案数。该数字可能很大,输出它对 1000000007 取模的结果。
    例如,输入:
    2 2 2
    1 2
    2 1
    程序应该输出:2
    再例如,输入:
    2 3 2
    1 2 3
    2 1 5
    程序应该输出:14(题目有点长)

      第一次看到这题目时,一个头两个大,卧槽,这么复杂的过程,而且当时还没有学算法。不过把题目看多几遍,慢慢的就看懂了他的意思。比如 格子矩阵为

    A B C

    D E F 那么小明可走的路线有 ABCF,ABEF,ADEF三种。而每一条路线又有不同的取法。所以我认为这道题可以分为渐进的两个步骤,一是找出所有小明可走的路线,而是算出每条路线可行的取宝方法数。 首先,对于第一个步骤,我们可以采用递归的方法,用动态数组(初始化动态数组的第一个值为0,原因在第二个步骤)记录路线每一格子的宝物价值,我创建了一个go方法,带有两个参数分别为当前格子坐标,在main方法里面调用go(0,0)开始取宝。go方法如下:

     

    public static void go(int i,int j){ //采用递归的方法做出类似树的遍历.  i为横坐标,j为纵坐标,比如上面B的坐标为(0,1)
      newList.add(r[i][j]);         //为动态数组添加宝物价值
      if(i==n-1 && j<m-1){     //如果i==n-1 && j<m-1,即走到上面的C,那么小明只能向下走
        go(i,j+1);
      }else if(j==m-1 && i<n-1){ //如果j==m-1 && i<n-1,即走到上面D,的那么小明只能向右走
        go(i+1,j);
      }
      else if(i==n-1&&j==m-1){ //如果到达最后一个格子,那么就进行对这条路线取值方法分析
        run(0); //进行线路取值分析-->run  (即第二个步骤)
      }else{ //如果j<m-1 && i<n-1,那么小明可以向右走也可以向下走
        go(i,j+1);
        go(i+1,j);
      }
      newList.remove(newList.size()-1); //当每一条路线分析完后,移除路线的最后一步。动态数组循环利用.不用为每一条路线声明一个动态数组
    }   

    这样第一个步骤就完成了, 第二个步骤:题目给出的第二个例子中有一条路线为1235,k为2。哎,还是直接上代码比较好说:

    public static void run(int num){                 
      for(int i = num+1;i<newList.size();i++){
        if(max<newList.get(i)){          //动态数组第一个值为零为了更好的使用递归,这样第个格子就可以比较
        p++;                                                       //p为记录当前小明取的宝物数,若当前格子宝物价值大于之前的拿的宝物,就拿,
        if(p==k){           //所取宝物数等于k那么count(总的方法数加一)
          count++;                              
        }else if(i==newList.size()-1){   //路线走完
        }else{                                   //进行下一步

           max = newList.get(i);      
          run(i);
        }
        p--;                                       //  可表示不取
      }
    }

    完整代码

    import java.util.Scanner;
    public class Main {
      public static Scanner read = new Scanner(System.in);
      static int n,m,k; //n表示矩阵的行数,m表示矩阵的列数,k表示小明所需要的宝物数
      static int[][] r ; //用二维数组表示n*m的矩阵
      static ArrayList<Integer> newList = new ArrayList(); //用动态数组储存每一步对应格子的宝物价值
      static int p = 0,max = 0; // p表示当前小明拿的宝物数
      private static int count = 0; //count表示方法数
      public static void main(String[] args){
        n = read.nextInt();m = read.nextInt();k = read.nextInt();
        r = new int[n][m];
        read.nextLine(); //读取下一行
        for(int i = 0; i<n ;i++){
          for(int j = 0; j<m ;j++){
            r[i][j] = read.nextInt();
          }
          read.nextLine();
        } //给矩阵附上对应的宝物价值
        go(0,0); //开始取宝物啦 ,0,0)这是每一步必走的格子
        System.out.print(count); //输出方法数
      }
      public static void go(int i,int j){ //采用递归的方法做出类似树的遍历
        newList.add(r[i][j]);
        if(i==n-1 && j<m-1){ //如果i==n-1 && j<m-1,那么小明只能向下走
          go(i,j+1);
        }else if(j==m-1 && i<n-1){ //如果j==m-1 && i<n-1,那么小明只能向右走
          go(i+1,j);
        }else if(i==n-1&&j==m-1){ //如果到达最后一个格子,那么就进行对这条路线取值方法分析
          max = 0;
          run(0); //进行线路取值分析-->run
        }else{ //如果j<m-1 && i<n-1,那么小明可以向右走也可以向下走
          go(i,j+1);
          go(i+1,j);
         }
        newList.remove(newList.size()-1); //当每一条路线分析完后,移除路线的最后一步
      }
      public static void run(int num){
        for(int i = num+1;i<newList.size();i++){
          if(max<newList.get(i)){
            p++;
            if(p==k){
            count++;
          }else if(i==newList.size()-1){
          }else{
            max = newList.get(i);
            run(i);
          }
           p--;
         }
      }
    }

     

  • 相关阅读:
    oracle lengthb
    layui-rp
    1709052基于框架新建 子项目
    echar 常用单词
    Leetcode 481.神奇字符串
    Leetcode 480.滑动窗口中位数
    Leetcode 479.最大回文数乘积
    Leetcode 477.汉明距离总和
    Leetcode 476.数字的补数
    Leetcode 475.供暖气
  • 原文地址:https://www.cnblogs.com/cyeye/p/4280233.html
Copyright © 2011-2022 走看看