地宫寻宝java_蓝桥杯 2014年 第五届 迷宫寻宝 详解(JAVA)

蓝桥杯 2014年 第五届 迷宫寻宝 详解(JAVA)

基础思路(DFS)

package provincial_2014B;

import java.util.Scanner;

/**

* 该题有两种做法:

* - dfs + 剪枝: 虽有优化,但还是速度较慢,但好入门

* - 动态规划(记忆性深搜实现):先搞清楚dfs,再了解dp

*

*/

public class Nine {

// 一般都把map数组定义为全局变量

private static int n,m,k;

private static int[][] map;

private static final int MOD = 1000000007;

// 题中告知要对MOD取余,显然较大,所以用long或double

private static long ans;

public static void main(String[] args) {

Scanner scan = new Scanner(System.in);

n = scan.nextInt();

m = scan.nextInt();

k = scan.nextInt();

map = new int[n][m];

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

for(int j = 0; j < m; j++) {

map[i][j] = scan.nextInt();

}

}

dfs(0, 0, 0, -1);

System.out.println(ans);

}

// 需要注意的是:x是横坐标,y是纵坐标,所以对应于数组的元素为map[y][x];

private static void dfs(int x, int y, int goods, int max) {

// 边界预防

if(x==m||y==n) {

return;

}

int now = map[y][x];

// 到达最终点

// ***注意:到达最终点后由于不会再进行判断拿不拿了

// *** 所以必须在这里再判断一次拿不拿

if(x==m-1&&y==n-1) {

if(goods==k || (goods==k-1&&max

ans++;

ans %= MOD;

}

return;

}

// 拿了,向下或向右走

if(max

dfs(x, y+1, goods+1, now);

dfs(x+1, y, goods+1, now);

}

// 没拿,向下或向右走

dfs(x+1, y, goods, max);

dfs(x, y+1, goods, max);

}

}

基础思路优化(剪枝)

当goods(已拿的宝物)比最终要拿到的宝物还多时,就return(不走了)。

package provincial_2014B;

import java.util.Scanner;

/**

* 该题有两种做法:

* - dfs + 剪枝: 虽有优化,但还是速度较慢,但好入门

* - 动态规划(记忆性深搜实现):先搞清楚dfs,再了解dp

*

*/

public class Nine {

// 一般都把map数组定义为全局变量

private static int n,m,k;

private static int[][] map;

private static final int MOD = 1000000007;

private static long ans;

public static void main(String[] args) {

Scanner scan = new Scanner(System.in);

n = scan.nextInt();

m = scan.nextInt();

k = scan.nextInt();

map = new int[n][m];

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

for(int j = 0; j < m; j++) {

map[i][j] = scan.nextInt();

}

}

dfs(0, 0, 0, -1);

System.out.println(ans);

}

// 需要注意的是:x是横坐标,y是纵坐标,所以对应于数组的元素为map[y][x];

private static void dfs(int x, int y, int goods, int max) {

// 边界预防

if(x==m||y==n||goods>k) {

return;

}

int now = map[y][x];

// 到达最终点

// ***注意:到达最终点后由于不会再进行判断拿不拿了

// *** 所以必须在这里再判断一次拿不拿

if(x==m-1&&y==n-1) {

if(goods==k || (goods==k-1&&max

ans++;

ans %= MOD;

}

return;

}

// 拿了,向下或向右走

if(max

dfs(x, y+1, goods+1, now);

dfs(x+1, y, goods+1, now);

}

// 没拿,向下或向右走

dfs(x+1, y, goods, max);

dfs(x, y+1, goods, max);

}

}

动态规划/记忆型递归

其实记忆型递归就是在刚刚剪枝的基础上再进行优化(剪枝)。

核心就是加入一个新数组cache用来缓存每一个子问题的解。其中,dfs有几个参数,cache就有几个维度。将每种情况看作一种状态。

package provincial_2014B;

import java.util.Scanner;

/**

* 该题有两种做法:

* - dfs + 剪枝: 虽有优化,但还是速度较慢,但好入门

* - 动态规划(记忆性深搜实现):先搞清楚dfs,再了解dp

*

*/

public class Nine {

// 一般都把map数组定义为全局变量

private static int n,m,k;

private static int[][] map;

private static final int MOD = 1000000007;

// 开个数组反映一一映射关系

private static long[][][][] cache;

public static void main(String[] args) {

Scanner scan = new Scanner(System.in);

n = scan.nextInt();

m = scan.nextInt();

k = scan.nextInt();

map = new int[n][m];

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

for(int j = 0; j < m; j++) {

map[i][j] = scan.nextInt();

}

}

//***注意:因为宝物的价值一开始传进去为-1,不满足下标规则

//*** 所以记录时要+1,所以最大下标也要+1

cache = new long[n][m][14][14];

// 为什么填充-1:因为ans有可能return0,在不满足条件时,

// 就可以看做该点已经走过,状态为0

for(int i = 0; i < n; i++)

for(int j = 0; j < m; j++)

for(int r = 0; r < 14; r++)

for(int q = 0; q < 14; q++)

cache[i][j][r][q]=-1;

long ans = dp(0, 0, 0, -1);

System.out.println(ans);

}

private static long dp(int x, int y, int goods, int max) {

// 边界预防+剪枝

if(x==m||y==n||goods>k) {

return 0;

}

if(cache[y][x][goods][max+1]!=-1) return cache[y][x][goods][max+1];

int now = map[y][x];

// 某个点的返回值(该点的状态/该点拿了几件货物)

// 由以下情况组成

long ans = 0;

// 到达最终点

// ***注意:到达最终点后由于不会再进行判断拿不拿了

// *** 所以必须在这里再判断一次拿不拿

if(x==m-1&&y==n-1) {

if(goods==k || (goods==k-1&&max

return 1;

}

return 0;

}

// 拿了,向下或向右走

if(max

ans += dp(x, y+1, goods+1, now);

ans += dp(x+1, y, goods+1, now);

}

// 没拿,向下或向右走

ans += dp(x+1, y, goods, max);

ans += dp(x, y+1, goods, max);

// 记录该点的值到缓存

cache[y][x][goods][max+1] = ans % MOD;

return cache[y][x][goods][max+1];

}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
鉴于提供的内容是一段包含三个不同的Java程序的代码,我无法提供一个完整的答案来回答你的问题。但是,我可以为你提供一些信息。 根据引用和引用的内容,这两个程序都涉及到动态规划的算法。引用中的程序解决了一个关于序列的最长递增子序列的问题,而引用中的程序解决了一个关于背包问题的二维动态规划的问题。 对于引用中的内容,它是一个程序解决的是一个最长上升子序列的问题。 根据提供的代码,这些程序可能是用来解决一些蓝桥杯竞赛的题目。然而,我无法提供更多关于具体问题的信息。 如果你需要帮助解决特定的问题,我建议你仔细阅读每个程序的代码并理解它们的功能,然后根据需要进行相应的修改。如果你有关于动态规划或蓝桥杯竞赛的更具体的问题,我会很愿意帮助你。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [蓝桥杯AcWing学习笔记 3-2简单DP的学习(附相关蓝桥真题:地宫取宝、波动数列)(Java)](https://blog.csdn.net/weixin_53407527/article/details/123122245)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值