蒜头君的城堡之旅

蒜国地域是一个n 行m 列的矩阵,下标均从1开始。蒜国有个美丽的城堡,在坐标(n,m)上,蒜头君在坐标(1,1) 的位置上。蒜头君打算出发去城堡游玩,游玩结束后返回到起点。在出发去城堡的路上,蒜头君只会选择往下或者往右走,而在返回的路上,蒜头君只会选择往上或者往左走,每次只能走一格。已知每个格子上都有一定数量的蒜味可乐,每个格子至多经过一次。

现在蒜头君请你来帮他计算一下,如何计划来回行程,可以收集到最多的蒜味可乐。

输入格式

第一行输入两个整数n,m(1n,m50),表示蒜国是一个n 行m 列的矩阵。

接下来输入n 行,每行输入m 个整数,代表一个n×m 的矩阵,每个整数代表对应位置上的蒜味可乐数量,每行的每两个整数之间用一个空格隔开。其中蒜头君的位置和城堡的位置上没有蒜味可乐,用0表示,其余位置上的整数范围在[1,100] 内。

输出格式

输出一行,输出一个整数,表示蒜头君在来回路上能收集到的蒜味可乐的最大值。

样例输入
3 3
0 2 9
4 8 6
2 7 0
样例输出
36

这个题目的主要矛盾点在于,去城堡的路上和在城堡回来的路上的权重应当是一样的,即如果取去时路上的最大值和相应的回来的路上的最大值并不能保证其和是最大值。

思路:

1. 想要达到一个坐标点,只有通过这个坐标点的上方或者左方进入,又已知路线不能重复,那么一旦从左方进入这个坐标,那么只能在上方离开这个坐标,反之亦然:从上方进入只能在左方离开。

2. 那么这个问题(去到(n, m)点并返回能取到的最多的可乐的数量)就可以分解为:从(1, 1)出发到(n - 1, m)路上取到的可乐加上从(n, m - 1)出发回到(1, 1)的路上取到的可乐数量之和的最大值(或者相反)。

3. 考虑到虽然出发和返回是两条路线,起始点不一样,但是最终连接的两个点却是一样的。那么就可以转化成这样:有两个人,同时在原点出发,目标都是城堡且两人路线不能重合,最后两个人可以取得的可乐的最大数量的和,就是这个题目的解。

用(x1,y1)和(x2,y2)来表示这两个点,那么合法的两个点应当是:

x1 != x2 && y1 != y2 (两点不能重复)

x1 + y1 == x2 + y2 (两人同时出发)

4.可以使用4维数组来表示这个问题的答案:

f[x1][y1][x2][y2]:表示在原点出发后,两人分别到达点(x1,y1)和(x2,y2)时所取到的可乐的和的最大值。

状态转移方程如下:

f[x1][y1][x2][y2] = Math.max(

                                Math.max(f[x1 - 1][y1][x2 - 1][y2], f[x1][y1 - 1][x2][y2 - 1])),

                                Math.max(f[x1][y1 - 1][x2 - 1][y2], f[x1 - 1][y1][x2][y2 - 1]))

                                + cola[x1][y1] + cola[x2][y2].

Java 代码:

import java.util.Scanner;

public class Castle {

	public static void main(String[] args) {
	    Scanner in = new Scanner(System.in);
            int n = in.nextInt(), m = in.nextInt();
	    int[][] cola  = new int[n + 1][m + 1];
	    for(int i = 1; i <= n; i++) {
		for(int j = 1; j <= m; j++) {
		    cola[i][j] = in.nextInt();
		}
	    }
	    in.close();
	    //用(x1,y1), (x2, y2)表示同时出发的两个点
            int x1 = 0, x2 = 0, y1 = 0, y2 = 0;

            int[][][][] f = new int[n + 1][m + 1][n + 1][m + 1];
		
            for(int i = 1; i <= n; i++) {
		for(int j = 1; j <= m; j++) {
		    for(int k = 1; k <= n; k++) {
	                int l = i + j - k;
			if(l <= 0 || l > m) {
		            continue;
			}else if(i == k && j == l) {
			    continue;
			}else {
			    x1 = i;
			    y1 = j;
			    x2 = k;
			    y2 = l;
			    f[x1][y1][x2][y2] = Math.max(Math.max(f[x1 - 1][y1][x2 - 1][y2], f[x1][y1 - 1][x2][y2 - 1]), 
                                                     Math.max(f[x1][y1- 1][x2 - 1][y2], f[x1 - 1][y1][x2][y2 - 1]))
                                                       + cola[x1][y1] + cola[x2][y2];
		        }					
	            }
	        }
	    }
	System.out.println(f[n - 1][m][n][m - 1]);		
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值