码迷,mamicode.com
首页 > 编程语言 > 详细

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

时间:2015-02-08 18:11:55      阅读:223      评论:0      收藏:0      [点我收藏+]

标签:

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

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

 

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

标签:

原文地址:http://www.cnblogs.com/cyeye/p/4280233.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!