算法题:方格取数(Java实现)

一、问题描述

设有N*N的方格图(N<=10),我们将其中的某些方格中填入正整数,而其他的方格中则放入数字0。
某人从图的左上角的A 点(1,1)出发,可以向下行走,也可以向右走,直到到达右下角的B点(N,N)。在走过的路上,他可以取走方格中的数(取走后的方格中将变为数字0)。
此人从A点到B 点共走两次,试找出2条这样的路径,使得取得的数之和为最大。

输入格式:
输入的第一行为一个整数N(表示N*N的方格图),接下来的每行有三个整数,前两个表示位置,第三个数为该位置上所放的数。一行单独的0表示输入结束。

输出格式:
只需输出一个整数,表示2条路径上取得的最大的和。

输入样例:

8
2 3 13
2 6 6
3 5 7
4 4 14
5 2 21
5 6 4
6 3 15
7 2 14
0 0 0

输出样例:

67

二、分析

这里需要注意的是i行0列,和0行j列的数据必须为0 (边界处理)
多线程同时dp。当做俩个人同时在矩阵中走;
x1,y1,表示第一个人的位置;
x2,y2,表示第二个人的位置;
dp[x1][y1][x2][y2]表示俩个人在对应的方格中时候取得的最大的数;
到达x1,y1有(x1-1,y1)(x1,y1-1)俩种状态;
到达x2,y2有(x2-1,y2)(x2,y2-1)俩种状态;

因此dp[x1][y1][x2][y2]就是这四种dp[][][][]里的最大值加上对应map[x1][y1],map[x2][y2]中的值即可,但是,要注意,如果俩个人站在同一个位置,则只加一个map即可,因为一个人取走后该位置就变为0了。

三、代码实现

import java.util.Scanner;

public class Test05 {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int N = sc.nextInt();
        int m, n, nums;
        //将初始的数组设置为11 * 11大小,如果直接设置为N*N,会造成数组越界
        int [][] s =new int[11][11];
        int [][][][] map = new int[11][11][11][11];
        while (true){
            m = sc.nextInt();
            n = sc.nextInt();
            nums = sc.nextInt();
            //跳出循环的条件(0,0,0)
            if (m == 0 && n == 0 && nums == 0){
                break;
            }
            s[m][n] = nums;
        }
        for (int x1 = 1; x1 <= N; x1++) {
            for (int y1 = 1; y1 <= N; y1++) {
                for (int x2 = 1; x2 <= N; x2++) {
                    for (int y2 = 1; y2 <= N; y2++) {
                        map[x1][y1][x2][y2] = Math.max(Math.max(map[x1-1][y1][x2-1][y2], map[x1-1][y1][x2][y2-1]),
                                Math.max(map[x1][y1-1][x2-1][y2], map[x1][y1-1][x2][y2-1]));
                        map[x1][y1][x2][y2] += s[x1][y1];
                        //如果两次都会经过同一个点,则加一次即可,以免造成重复
                        //只要经过的点不相同,就可以直接添加
                        if (x1 != x2 && y1 != y2){
                            map[x1][y1][x2][y2] += s[x2][y2];
                        }
                    }
                }
            }
        }
        System.out.println(map[N][N][N][N]);
    }
}

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值