一个算法题,又是小明。囧

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

原文如下:地宫取宝,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--;
     }
  }
}

时间: 2024-10-18 13:08:43

一个算法题,又是小明。囧的相关文章

(关于一个算法题的两点新思路)给你一组字符串 如 {5,2,3,2,4,5,1,2,1,5},让你输出里面出现次数最多且数值最大的一个,出现几次

在网上看到一个算法题,不是很难,搜一下也有解决办法,但是一般都是几层for循环,试着写了下 /** * 给你一组字符串 如 {5,2,3,2,4,5,1,2,1,5},让你输出里面出现次数最多且数值最大的一个,出现几次 * 优点:时间复杂度为O(n) * 缺点:产生一些多余的空间,如 6,7,8没有的数也会分配一个数组空间,但是基本可以忽略 * 限制:需要预先知道最大的值是多少,或者说小于多少,这样才好确定预先分配一个数组长度是多少 */ public static void method1()

2015阿里秋招其中一个算法题(经典)

写一个函数,输入一个二叉树,树中每个节点存放了一个整数值,函数返回这棵二叉树中相差最大的两个节点间的差值绝对值.请注意程序效率 这是2015阿里秋招的一个在线笔试题 实现方法很简单,遍历一遍二叉树,找出最大最小,一相减就可以求出最大的差值 之前在做题的时候居然写递归的方法求值,后面测试了一下,果然结果不对 只要是非递归的的方法遍历都可以很容易找出最大值最小值,效率也比较高,时间复杂度为O(n). 下面是我用非递归从上往下遍历二叉树的方法 用队列容器即可方便实现. 我写的代码: #include

一个算法题:括号匹配问题。

问:给予一个字符串为:']]][]]]][[[[[[]]]]',请写出程序求出其有多少对'[]'? 一般这种问题都是想让你通过数据结构去处理,仔细回想一下我们学过的数据结构,栈的先进后出是否能处理这个问题?将字符串遍历,遇到左方括号 '[' 时将其压入栈中,遇到右方括号 ']'时取出栈顶元素匹配,并将对数加1,这样最后我们就求出来能有多少对方括号了. 栈的示意图: 流程图: 通过分析,我们使用PHP编码实现这个功能: //括号匹配问题 $str = ']]][]]]][[[[[[]]]]'; /

python遇到一个算法题 , 顺手做了 ,但是跑不出结果......

def d(i): sumInt = 0 sumInt = sumInt + start if i % start == 0 for start in range(1,i) return sumInt print(str(sum([d(i) for i in range(1, 10**12)]))[-12:]) 求1<=i<=10**12范围内所有d(i)的和的末12位,d(i)表示i的正约数的和,i为整数

南阳acm-50-爱摘苹果的小明(水题)

爱摘苹果的小明 时间限制:1000 ms  |  内存限制:65535 KB 难度:1 描述 小明家的院子里有一棵苹果树,每到秋天树上就会结出10个苹果.苹果成熟的时候,小明就会跑去摘苹果.小明有个30厘米高的板凳,当她不能直接用手摘到苹果的时候,就会踩到板凳上再试试. 现在已知10个苹果到地面的高度,以及小明把手伸直的时候能够达到的最大高度,请帮小明算一下她能够摘到的苹果的数目.假设她碰到苹果,苹果就会掉下来. 输入 第一行输入N(0<N<100)表示测试数据组数,接下来每组测试输入包括两行

一道有趣的算法题:仿照Excel的列编号,给定一个数字,输出该列编号字符串

       By Long Luo 最近遇到一个算法题: 仿照Excel的列编号,给出一个数字,输出该列编号字符串. 例如:A对应1,Z对应26,AA对应27,AZ对应52 ...... 这个题目是一个典型的26进制思路去处理,但是这个题目里面有很多陷阱,在1, 26, 52等特殊情况进行考虑,经过晚上接近1个小时的编写,完成的代码如下: C++代码如下: #include <iostream> #include <string.h> using namespace std; /

HDU 小明系列故事——师兄帮帮忙 快速幂

小明系列故事--师兄帮帮忙 Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others) Total Submission(s): 4850    Accepted Submission(s): 1275 Problem Description 小明自从告别了ACM/ICPC之后,就开始潜心研究数学问题了,一则可以为接下来的考研做准备,再者可以借此机会帮助一些同学,尤其是漂亮的师妹.这不,班

hdu4506 小明系列故事——师兄帮帮忙 (规律模拟+快速幂)

Problem Description http://acm.hdu.edu.cn/showproblem.php?pid=4506 小明自从告别了ACM/ICPC之后,就开始潜心研究数学问题了,一则可以为接下来的考研做准备,再者可以借此机会帮助一些同学,尤其是漂亮的师妹.这不,班里唯一的女生又拿一道数学题来请教小明,小明当然很高兴的就接受了.不过等他仔细读题以后,发现自己也不会做,这下小明囧了:如果回复说自己不懂,岂不是很没面子? 所以,他现在私下求你帮忙解决这道题目,题目是这样的: 给你n个

杭电 4506 小明系列故事——师兄帮帮忙【快速幂取模】

题目:小明自从告别了ACM/ICPC之后,就开始潜心研究数学问题了,一则可以为接下来的考研做准备,再者可以借此机会帮助一些同学,尤其是漂亮的师妹.这不,班里唯一的女生又拿一道数学题来请教小明,小明当然很高兴的就接受了.不过等他仔细读题以后,发现自己也不会做,这下小明囧了:如果回复说自己不懂,岂不是很没面子? 所以,他现在私下求你帮忙解决这道题目,题目是这样的: 给你n个数字,分别是a1,a2,a3,a4,a5……an,这些数字每过一个单位时间就会改变,假设上一个单位时间的数字为a1’,a2’,a