算法笔记_135:格子取数问题(Java)

目录

1 问题描述

2 解决方案

 


1 问题描述

有n*n个格子,每个格子里有正数或者0,从最左上角往最右下角走,只能向下和向右走,一共走两次(即从左上角往右下角走两趟),把所有经过的格子里的数加起来,求总和的最大值。如果两次经过同一个格子,则最后求得的总和中该格子中的数只加一次。


2 解决方案

此处采用动态规划法,可以较大的提高时间效率。

具体代码如下:

package com.liuzhen.practice;

import java.util.Scanner;

public class Main {

    public boolean judge(int s, int i ,int j ,int len) {
        int x1 = s - i, x2 = s - j;
        if(x1 >= 0 && x1 < len && x2 >= 0 && x2 < len && i >= 0 && j >= 0 && i < len && j < len)
            return true;
        return false;
    }

    public int getValue(int[][][] dp, int s, int i , int j, int len) {
        if(judge(s, i, j, len))
            return dp[s][i][j];
        return -1;
    }

    public void getResult(int[][] value) {
        int len = value.length;
        int[][][] dp = new int[len * 2][len][len];
        dp[0][0][0] = value[0][0];
        for(int s = 1;s <= len * 2 - 2;s++) {
            for(int i = 0;i < len;i++) {
                for(int j = 0;j < len;j++) {
                    if(judge(s, i, j, len)) {
                        if(i != j)
                            dp[s][i][j] = Math.max(Math.max(getValue(dp,s-1,i-1,j-1,len),getValue(dp,s-1,i,j,len)),
                                    Math.max(getValue(dp,s-1,i-1,j,len), getValue(dp,s-1,i,j-1,len))) + value[i][s-i] + value[j][s-j];
                        else
                            dp[s][i][j] = Math.max(getValue(dp,s-1,i-1,j-1,len),
                                    Math.max(getValue(dp,s-1,i-1,j,len), getValue(dp,s-1,i,j,len))) + value[i][s-i];
                    }
                }
            }
        }
        System.out.println(dp[2 * len - 2][len - 1][len - 1]);
        return;
    }

    public static void main(String[] args) {
        Main test = new Main();
        Scanner in = new Scanner(System.in);
        int n = in.nextInt();
        int[][] value = new int[n][n];
        for(int i = 0;i < n;i++)
            for(int j = 0;j < n;j++)
                value[i][j] = in.nextInt();
        test.getResult(value);
    }
}

运行结果:

6
0 0 3 0 2 0
0 0 3 0 0 0
0 0 3 0 0 0
0 0 0 0 4 0
0 0 0 0 4 0
0 0 3 0 0 0
22

8
0 0 0 0 0 0 0 0
0 0 13 0 0 6 0 0
0 0 0 0 7 0 0 0
0 0 0 14 0 0 0 0
0 21 0 0 0 4 0 0
0 0 15 0 0 0 0 0
0 14 0 0 0 0 0 0
0 0 0 0 0 0 0 0
67

参考资料:

1.《编程之法面试和算法心得》  July 著

时间: 2024-08-07 12:50:38

算法笔记_135:格子取数问题(Java)的相关文章

算法笔记_183:历届试题 九宫重排(Java)

目录 1 问题描述 2 解决方案   1 问题描述 问题描述 如下面第一个图的九宫格中,放着 1~8 的数字卡片,还有一个格子空着.与空格子相邻的格子中的卡片可以移动到空格中.经过若干次移动,可以形成第二个图所示的局面. 我们把第一个图的局面记为:12345678. 把第二个图的局面记为:123.46758 显然是按从上到下,从左到右的顺序记录数字,空格记为句点. 本题目的任务是已知九宫的初态和终态,求最少经过多少步的移动可以到达.如果无论多少步都无法到达,则输出-1. 输入格式 输入第一行包含

算法笔记_170:历届试题 分糖果(Java)

目录 1 问题描述 2 解决方案   1 问题描述 问题描述 有n个小朋友围坐成一圈.老师给每个小朋友随机发偶数个糖果,然后进行下面的游戏: 每个小朋友都把自己的糖果分一半给左手边的孩子. 一轮分糖后,拥有奇数颗糖的孩子由老师补给1个糖果,从而变成偶数. 反复进行这个游戏,直到所有小朋友的糖果数都相同为止. 你的任务是预测在已知的初始糖果情形下,老师一共需要补发多少个糖果. 输入格式 程序首先读入一个整数N(2<N<100),表示小朋友的人数. 接着是一行用空格分开的N个偶数(每个偶数不大于1

算法笔记_187:历届试题 网络寻路(Java)

目录 1 问题描述 2 解决方案   1 问题描述 问题描述 X 国的一个网络使用若干条线路连接若干个节点.节点间的通信是双向的.某重要数据包,为了安全起见,必须恰好被转发两次到达目的地.该包可能在任意一个节点产生,我们需要知道该网络中一共有多少种不同的转发路径. 源地址和目标地址可以相同,但中间节点必须不同. 如下图所示的网络. 1 -> 2 -> 3 -> 1 是允许的 1 -> 2 -> 1 -> 2 或者 1 -> 2 -> 3 -> 2 都是

算法笔记_219:泊松分酒(Java)

目录 1 问题描述 2 解决方案   1 问题描述 泊松是法国数学家.物理学家和力学家.他一生致力科学事业,成果颇多.有许多著名的公式定理以他的名字命名,比如概率论中著名的泊松分布. 有一次闲暇时,他提出过一个有趣的问题,后称为:"泊松分酒".在我国古代也提出过类似问题,遗憾的是没有进行彻底探索,其中流传较多是:"韩信走马分油"问题. 有3个容器,容量分别为12升,8升,5升.其中12升中装满油,另外两个空着.要求你只用3个容器操作,最后使得某个容器中正好有6升油.

算法笔记_022:字符串的旋转(Java)

目录 1 问题描述 2 解决方案 2.1 蛮力移位 2.2 三步反转 1 问题描述 给定一个字符串,要求将字符串前面的若干个字符移到字符串的尾部.例如,将字符串"abcdef"的前3个字符'a'.'b'和'c'移到字符串的尾部,那么原字符串将变成"defabc".请写一个函数实现此功能. 2 解决方案 2.1 蛮力移位 此方法将需要移动的字符一个一个地移到字符串的尾部,具体代码如下: package com.liuzhen.string_1; public clas

算法笔记_048:找零问题(Java)

目录 1 问题描述 2 解决方案 2.1 动态规划法   1 问题描述 现需找零金额为n,则最少需要用多少面值为d1 < d2 < d3 < ... < dm的硬币?(PS:假设这m种面值d1 < d2 < d3 < ... < dm的硬币,其中d1 = 1,且每种硬币数量无限可得) 2 解决方案 2.1 动态规划法 本文编码思想参考自<算法设计与分析基础>第三版,具体讲解如下: 具体代码如下: package com.liuzhen.chapt

算法笔记_232:提取拼音首字母(Java)

目录 1 问题描述 2 解决方案   1 问题描述 在很多软件中,输入拼音的首写字母就可以快速定位到某个词条.比如,在铁路售票软件中,输入: "bj"就可以定位到"北京".怎样在自己的软件中实现这个功能呢?问题的关键在于:对每个汉字必须能计算出它的拼音首字母. GB2312汉字编码方式中,一级汉字的3755个是按照拼音顺序排列的.我们可以利用这个特征,对常用汉字求拼音首字母. GB2312编码方案对每个汉字采用两个字节表示.第一个字节为区号,第二个字节为区中的偏移号

算法笔记_221:串的简单处理(Java)

目录 1 问题描述 2 解决方案   1 问题描述 串的处理在实际的开发工作中,对字符串的处理是最常见的编程任务.本题目即是要求程序对用户输入的串进行处理.具体规则如下:1. 把每个单词的首字母变为大写.2. 把数字与字母之间用下划线字符(_)分开,使得更清晰3. 把单词中间有多个空格的调整为1个空格. 例如:用户输入:you and me what cpp2005program则程序输出:You And Me What Cpp_2005_program 用户输入:this is a 99cat

算法笔记_194:历届试题 翻硬币(Java)

目录 1 问题描述 2 解决方案   1 问题描述 问题描述 小明正在玩一个"翻硬币"的游戏. 桌上放着排成一排的若干硬币.我们用 * 表示正面,用 o 表示反面(是小写字母,不是零). 比如,可能情形是:**oo***oooo 如果同时翻转左边的两个硬币,则变为:oooo***oooo 现在小明的问题是:如果已知了初始状态和要达到的目标状态,每次只能同时翻转相邻的两个硬币,那么对特定的局面,最少要翻动多少次呢? 我们约定:把翻动相邻的两个硬币叫做一步操作,那么要求: 输入格式 两行等