dynamic programming 部分问题
程序员文章站
2024-03-23 23:24:58
...
Code:
递归版本:
import java.util.Scanner;
public class z1 {
static int n;
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
n = input.nextInt(); // 输入硬币的数量
int[] coins = new int[n + 1];
coins[0] = 0;
for (int i = 1; i <= n; i++) { // 硬币从下标为1开始,直到 n
coins[i] = input.nextInt();
}
System.out.println(solve(coins, 1)); // 解决
}
// 递归有两种情况, 选和不选当前的位置
public static long solve(int[] coins, int sign) {
// 位置合法的情况下
if (sign >= 1 && sign <= n) {
// 选择当前位置,然后判断相邻一个硬币的可能性, 不选择当前位置,递归判断相邻两个硬币的情况(选or不选)
return Math.max(coins[sign] + solve(coins, sign + 2), solve(coins, sign + 1));
}
return 0;
}
}
动态规划:
package dynamic_2019_02_18;
import java.util.Scanner;
public class z1_1 {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
int n = input.nextInt(); // 输入硬币的数量
int[] coins = new int[n + 1];
for (int i = 1; i <= n; i++) { // 硬币从下标为1开始,直到 n
coins[i] = input.nextInt();
}
System.out.println(solve(coins, n));
}
// 递归改成了动态规划两种情况, 选和不选当前的位置
public static int solve(int[] coins, int n) {
int[][] value = new int[n][n + 2];
for (int i = 1; i < n; i++) {
for (int j = 1; j <= n; j++) {
if (j == n) { // 最后硬币(边界情况),选择,不选
value[i][j] = Math.max(coins[j] + value[i - 1][j - 2], value[i - 1][j - 1]);
} else if (j == 1) {
value[i][j] = coins[j];
} else {
value[i][j] = Math.max(coins[j] + value[i - 1][j - 2], value[i - 1][j - 1]);
}
}
}
int maxValue = 0;
for (int i = 0; i <= n + 1; i++) {
maxValue = Math.max(maxValue, value[n - 1][i]);
}
return maxValue;
}
// 动态规划 优化
public int getMaxGold(int w[], int n) {
int f[][] = new int[n + 1][2];
f[0][0] = 0; // 当前位置不选择的最大值
f[0][1] = w[0]; // 当前位置选择的最大值
for (int i = 1; i < n; ++i) {
f[i][0] = Math.max(f[i - 1][0], f[i - 1][1]);
f[i][1] = f[i - 1][0] + w[i];
}
return Math.max(f[n - 1][0], f[n - 1][1]);
}
}
递归版本:
package dynamic_2019_02_18;
import java.util.Scanner;
public class z2 {
/*
* 题目是这个样子的 年份T 工作的数量M 可以更换工作的次数S 工资的二维数组salary[M + 1][T + 1]
*/
static int T, M, S;
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
T = input.nextInt(); // 输入年数
M = input.nextInt(); // 输入工作的数量
S = input.nextInt(); // 输入可以更换工作的次数
int[][] salary = new int[M + 1][T + 1]; // 工作对应年份的工资
for (int i = 1; i <= M; i++) {
for (int j = 1; j <= T; j++) {
salary[i][j] = input.nextInt(); // 工作i 在第j年的工资
}
}
long maxSalary = 0;
for (int i = 1; i <= M; i++) { // 第一年选择的工作
maxSalary = Math.max(maxSalary, salary[i][1] + solve(salary, i, 2, 0));
}
System.err.println("获得的最大工资是:" + maxSalary);
}
// 工资数组、选择的工作 s、当前年份 t、更换工作的次数
public static long solve(int[][] salary, int s, int t, int num) {
long maxNum = 0;
if (t <= T) {
// 不更换工作
if (num <= S) { // 无法在更换工作或不更换的情况下,继续当前的工作获得的工资
maxNum = salary[s][t] + solve(salary, s, t + 1, num);
}
if (num < S) {
long tmpSalary = 0; // 更换工作 获得的最大工资
for (int i = 1; i <= M; i++) {
if (i != s) {
tmpSalary = Math.max(tmpSalary, salary[i][t] + solve(salary, i, t + 1, num + 1));
}
}
// 不更换工作和更换工作获得的最大工资
maxNum = Math.max(tmpSalary, maxNum);
}
return maxNum;
}
return maxNum;
}
}
动态规划:
package dynamic_2019_02_18;
import java.util.Scanner;
public class z2_2 {
/*
* 题目是这个样子的 年份T 工作的数量M 可以更换工作的次数S 工资的二维数组salary[T][M]
*/
static int T, M, S;
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
T = input.nextInt(); // 输入年数
M = input.nextInt(); // 输入工作的数量
S = input.nextInt(); // 输入可以更换工作的次数
int[][] salary = new int[T][M]; // 工作对应年份的工资
for (int i = 0; i < M; i++) {
for (int j = 0; j < T; j++) {
salary[i][j] = input.nextInt(); // 工作i 在第j年的工资
}
}
System.err.println("获得的最大工资是:" + solve(salary, T, M, S));
}
// 工作数组(某年,某职业的工资)、 T年、 m 职业、 S更换工作次数
public static int solve(int salary[][], int T, int M, int S) {
int f[][][] = new int[T][M][S + 1]; // 存储某年某职业更换工作次数的最大工资
int g[][] = new int[T][S + 1]; // 某年里,更换了多少次工作的最大工资
// 第1年,所有职业的最高工资等于当前的工资
for (int j = 0; j < M; j++) {
f[0][j][0] = salary[j][0];
g[0][0] = Math.max(g[0][0], f[0][j][0]);
}
for (int i = 1; i < T; i++) { // 寻找i年中得最高的工资
for (int j = 0; j < M; j++) { // 职业j的最大工资情况
for (int k = 0; k <= i && k <= S; k++) { // 更换工作次数 (一年换一次,而且有最大换工作的次数的限制)
f[i][j][k] = Math.max(f[i][j][k], f[i - 1][j][k] + salary[i][j]); // 不更换工作的情况
if (k >= 1) {
f[i][j][k] = Math.max(f[i][j][k], g[i - 1][k - 1] + salary[i][j]); // 更换工作的情况,(存在覆盖)保留最大的
}
}
}
// 一年结束,结算工资,(某职业,换工作次数的最大工资)
for (int j = 0; j < M; j++) {
for (int k = 0; k <= S; ++k) {
g[i][k] = Math.max(g[i][k], f[i][j][k]);
}
}
}
int ans = 0;
for (int j = 0; j < M; j++) {
for (int k = 0; k <= S; k++) {
ans = Math.max(ans, f[T - 1][j][k]); // 找出最后一年的最大的工资(最后一年的所有职业中)
// ans = Math.max(ans, g[j][k]); // 等价于这个
}
}
return ans;
}
}
该题目的欧洲版本的递归改成动态规划自己没有思路,博客记录
递归版本:
package dynamic_2019_02_18;
import java.util.Scanner;
public class z3_3 {
static int n;
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
n = input.nextInt();
// 输入游戏的参数 n * n的地图
int[][] map = new int[n + 1][n + 1];
boolean[][] flag = new boolean[n + 1][n + 1];
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
map[i][j] = input.nextInt();
flag[i][j] = false;
}
}
long AmericanMaxSum = Long.MIN_VALUE;
long EuropeanManSum = Long.MIN_VALUE;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
AmericanMaxSum = Math.max(AmericanMaxSum, AmericanSolve(map, i, j));
EuropeanManSum = Math.max(EuropeanManSum, EuropeanSolve(map, flag, i, j));
}
}
System.out.println("AmericanMaxSum = " + AmericanMaxSum);
System.out.println("EuropeanManSum = " + EuropeanManSum);
}
// 美国的只能选择一个位置,然后选择下面或者右边
public static long AmericanSolve(int[][] map, int i, int j) {
// 如果范围合法的话、选择当前位置,同时选择向下走或者向右走最大的一步
if (1 <= i && i <= n && 1 <= j && j <= n) {
return map[i][j] + Math.max(AmericanSolve(map, i + 1, j), AmericanSolve(map, i, j + 1));
}
return 0;
}
// 欧洲版本的可以选择下面、左边、右边、但是不能重复选取
public static long EuropeanSolve(int[][] map, boolean[][] flag, int i, int j) {
// 如果范围合法的话、且没有走过的话、选择当前位置,同时选择向下、向左、向右走最大的一步
if (1 <= i && i <= n && 1 <= j && j <= n && !flag[i][j]) {
flag[i][j] = true;
long down = map[i][j] + EuropeanSolve(map, flag, i + 1, j);
long left = map[i][j] + EuropeanSolve(map, flag, i, j - 1);
long right = map[i][j] + EuropeanSolve(map, flag, i, j + 1);
flag[i][j] = false;
return Math.max(down, Math.max(left, right));
}
return 0;
}
}
动态规划:
package dynamic_2019_02_18;
import java.util.Scanner;
public class z3 {
static int n;
static int value[][], value1[][]; // 美国玩法、欧洲玩法
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
n = input.nextInt();
// 输入游戏的参数 n * n的地图
int[][] map = new int[n + 1][n + 1];
boolean[][] flag = new boolean[n + 1][n + 1];
value = new int[n + 1][n + 1]; // 美国玩法的记录
value1 = new int[n + 1][n + 1]; // 欧洲玩法的记录 // 没有思路。 递归怎么修改
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
map[i][j] = input.nextInt();
flag[i][j] = false;
}
}
System.out.println("美国玩法的值是:" + AmericanSolve(map));
long EuropeanManSum = Long.MIN_VALUE;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
EuropeanManSum = Math.max(EuropeanManSum, EuropeanSolve(map, flag, i, j));
}
}
System.out.println("欧洲玩法的值是:" + EuropeanManSum);
}
// 美国的当前位置,只能从左边或者上面来到 、 如果都是负值(左边、上面)的话,我就不选择
public static int AmericanSolve(int[][] map) {
value[1][1] = map[1][1];
for (int i = 2; i <= n; i++) { // 对第1行第i列的数据进行处理、 只能从上面来
value[1][i] = map[1][i] + Math.max(0, value[1][i - 1]);
}
for (int i = 2; i <= n; i++) { // 对第i行第1列的数据进行处理,只能从左边来
value[i][1] = map[i][1] + Math.max(0, value[i - 1][1]);
}
// 其余情况 当前的元素 可以来至左边,或者上面, 选择最大的一个
for (int i = 2; i <= n; i++) {
for (int j = 2; j <= n; j++) {
int tmp = Math.max(value[i - 1][j], value[i][j - 1]);
value[i][j] = map[i][j] + Math.max(0, tmp); // 上面,左边的值和0那个大,选择最大的
}
}
int maxValue = Integer.MIN_VALUE;
for (int i = 1; i <= n; i++) {
maxValue = Math.max(maxValue, Math.max(value[n][i], value[i][n]));
}
return maxValue;
}
// 欧洲版本的可以选择下面、左边、右边、但是不能重复选取
public static long EuropeanSolve(int[][] map, boolean[][] flag, int i, int j) {
// 如果范围合法的话、且没有走过的话、选择当前位置,同时选择向下、向左、向右走最大的一步
if (1 <= i && i <= n && 1 <= j && j <= n && !flag[i][j]) {
flag[i][j] = true;
long down = map[i][j] + EuropeanSolve(map, flag, i + 1, j);
long left = map[i][j] + EuropeanSolve(map, flag, i, j - 1);
long right = map[i][j] + EuropeanSolve(map, flag, i, j + 1);
flag[i][j] = false;
return Math.max(down, Math.max(left, right));
}
return 0;
}
}
别人的代码,自己没有思路,记录下来
推荐阅读
-
dynamic programming 部分问题
-
Webwork部分OGNL标签在GlassFish上的异常的问题 博客分类: 默认类别 WebworkGlassfishJSPWebXML
-
(M)Dynamic Programming:464. Can I Win
-
linux下部分网站因DNS问题无法访问,修改DNS 博客分类: linux使用积累 grailslinuxifconfigdnsgroovyq
-
Bitmasking and Dynamic Programming 实例 :Count ways to assign unique cap to every person
-
iis访问出现各种问题(Vs访问正常)的部分处理方法详细整理
-
iis访问出现各种问题(Vs访问正常)的部分处理方法详细整理
-
STM32 cubeMX 前期项目未生成部分模块,后期需要添加功能模块时出现L6218E错误问题的解决方法
-
使用 C# 中的 dynamic 关键字调用类型方法时可能遇到的各种问题
-
Android开发中调用系统相册上传图片到服务器OPPO等部分手机上出现短暂的显示桌面问题的解决方法