大家好,我是晴天学长,dp版的来啦,可以是受益匪浅啊,需要的小伙伴可以关注支持一下哦!后续会继续更新的。💪💪💪
1) .迷宫逃脱
迷官逃脱[算法赛]
问题描述
在数学王国中,存在- -个大小为N x M的神秘迷言。第i行第j个位置坐标为(i,j),每个位置(i;,j) (1≤i≤N,1≤j≤M)都对应着一个正整数Aij。迷宫的左上角坐标为(1,1), 右下角坐标为(N,M)。
小蓝初始位于坐标(1,1),并携带著Q把密匙。他的目标是移动到迷言的终点,即坐标(N, M)处。但是通往迷宫尽头的道路并不是一-帆风顺的, 在前进的过程中,他遇到了一些奇特的规则。
规则如下:
1.小蓝每次只能向右移动一个位置或向下移动一个位置。
2.当小蓝所在位置的数和下一步移动位置的数互质时,会有一扇封闭的铁门, 小蓝需要消耗-把密匙来打开铁门,打开铁门后,这把钥匙将被摧毁。如果没有密匙,小蓝将无法移动到该位置。
你需要输出小蓝从起点到终点路径之和的最大值,如果无法从起点到达终点,输出-1
。
输入格式
第一行输入包含3个整数N, M, Q,分别为迷言的大小和密匙的数量。
接下来输入N行,每行M个整数,为迷言上的数值。
输出格式
输出仅一-行,包含-个整数,表示管案。
样例输入
331
139
样例输出
28
2) .算法思路
迷宫逃脱(DP版)
1.用快读快输接收数据。
2.建立矩阵
3.打表,建立一个三维的dp表。
4.状态转移方程
1.从上面来
int floor=
2.从左面来
int right=
3.状态转移方程
dp[i][j][k] = Math.,max();
4.输出dp[n][m][k](带循环)。
3).算法步骤
1.读取输入的N、M和Q的值(迷宫的尺寸和最大钥匙数量)。
2.创建一个名为"grid"的二维网格数组,用于存储迷宫中每个单元格的值。
3.初始化动态规划数组"dp",其维度为[1100][1100][4],用于存储不同钥匙数量下每个位置的最大分数。
4.读取迷宫中每个单元格的值,并将其存储在"grid"数组中。
5.在"dp"数组中设置起始位置(1, 1)的初始值。因为它是起始位置,所以分数等于该单元格的值。
6.开始动态规划过程,遍历迷宫中的每个单元格。
- 对于每个单元格,遍历钥匙数量(从0到Q),计算在给定钥匙数量下到达该单元格的最大分数。
- 检查是否可以从上方的单元格移动到当前单元格(即(i-1, j))或从左侧的单元格移动到当前单元格(即(i, j-1))。
- 如果可以从上方单元格移动,根据上方单元格的分数和当前单元格的值更新当前单元格的最大分数。
- 如果可以从左侧单元格移动,根据左侧单元格的分数和当前单元格的值更新当前单元格的最大分数。
- 重复步骤6到步骤10,遍历迷宫中的所有单元格。
7.找到最后一行和最后一列的单元格中不同钥匙数量下的最大分数。
8.将最大分数作为结果进行打印输出。如果最大分数小于或等于0,则输出-1。
9.刷新输出。
4). 代码实例
package LanQiaoTest.动态规划;
import jdk.swing.interop.SwingInterOpUtils;
import java.io.*;
public class 迷宫逃脱_DP {
static BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
static PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
static long dp[][][] = new long[1100][1100][4];
static String[] lines;
public static void main(String[] args) throws IOException {
lines = in.readLine().split(" ");
int N = Integer.parseInt(lines[0]);
int M = Integer.parseInt(lines[1]);
int Q = Integer.parseInt(lines[2]);
long[][] grid = new long[N + 10][M + 10];
// 接收数据
for (int i = 1; i <= N; i++) {
lines = in.readLine().split(" ");
for (int j = 1; j <= M; j++) {
grid[i][j] = Integer.parseInt(lines[j - 1]);
}
}
//起点赋初值(因为起点没有上一个的状态,自己就是自己)
for (int i = 0; i <= Q; i++) {
dp[1][1][i] = grid[1][1];
}
//开始打表
for (int i = 1; i <= N; i++) {
for (int j = 1; j <= M; j++) {
for (int k = 0; k <= Q; k++) {
int floor = gcd((int) grid[i][j], (int) grid[i][j - 1]) == 1 ? 1 : 0;
int left = gcd((int) grid[i][j], (int) grid[i - 1][j]) == 1 ? 1 : 0;
//注意钥匙不能超了
//上面来
//是质数,必须有钥匙。
if (k - floor >= 0 && dp[i][j - 1][k - floor] != 0) {
dp[i][j][k] = Math.max(dp[i][j][k], dp[i][j - 1][k - floor] + grid[i][j]);
}
//左面来,注意更新最大值
if (k - left >= 0 && dp[i - 1][j][k - left] != 0) {
dp[i][j][k] = Math.max(dp[i][j][k], dp[i - 1][j][k - left] + grid[i][j]);
}
}
}
}
//找到终点的最大值
long result = 0;
for (int i = 0; i <= Q; i++) {
result = Math.max(result, dp[N][M][i]);
}
out.println(result <= 0 ? -1 : result);
out.flush();
}
private static int gcd(int a, int b) {
return b == 0 ? a : gcd(b, a % b);
}
}
4).总结
- 越界的地方不能算进去,不然不可达到的地方也会加入答案中。
试题链接: