AcWing 3326. 最大硬币数 c++和Java实现

18 篇文章 0 订阅
17 篇文章 0 订阅
文章描述了一个关于在矩阵中寻找最优路径收集最多硬币的问题,Mike可以从任何方格开始,沿着斜率为-1的路径移动,目标是找到能收集到最多硬币的路径。解题思路涉及动态规划,通过比较不同斜线上硬币的累计值来找出最大值。
摘要由CSDN通过智能技术生成

题目

Mike 有一个 N 行 N 列的方格矩阵。

位于第 i 行第 j 列的方格的位置坐标表示为 (i,j)。

矩阵左上角方格的坐标即为 (1,1)。

每个方格中都包含一定数量的硬币,Mike 只有到达一个方格内时,方可收集方格中的硬币。

Ci,j 表示第 i 行第 j 列的方格中的硬币数量。

当 Mike 处于方格 (i,j) 时,他可以选择移动至方格 (i−1,j−1) 或方格 (i+1,j+1) 中,前提是所选择的方格位于矩阵边界内,且之前没有到达过。

Mike 可以选择从任意方格开始移动,也可以选择在移动至任意方格时结束移动。

Mike 希望尽可能多的收集硬币。

请帮助他确定他可以收集的最大硬币数量。

输入格式
第一行包含整数 T,表示共有 T 组测试数据。

每组数据第一行包含整数 N。

接下来 N 行,每行包含 N 个整数,其中第 i 行第 j 列的整数表示 Ci,j。

输出格式
每组数据输出一个结果,每个结果占一行。

结果表示为 Case #x: y,其中 x 为组别编号(从 1 开始),y 为可以收集的最大硬币数量。

数据范围
60% 的数据满足,1≤T≤100,1≤N≤100。
另外 40% 的数据满足,1≤T≤10,1≤N≤1000。
100% 的数据满足,0≤Ci,j≤107。

输入样例:

2
3
1 2 5
3 6 1
12 2 7
5
0 0 0 0 0
1 1 1 1 0
2 2 2 8 0
1 1 1 0 0
0 0 0 0 0

输出样例:

Case #1: 14
Case #2: 9

样例解释
对于测试数据 1,Mike 可以选择的行进路径为 (1,1)→(2,2)→(3,3),可收集到的最大硬币数量为 14。

对于测试数据 2,Mike 可以选择的行进路径为 (2,3)→(3,4),可收集到的最大硬币数量为 9。

解题思路

题目需要求出 Mike 在行进路线上所能收集的最大硬币数量;

由于 Mike 只能移动至方格 (i−1,j−1) 或方格 (i+1,j+1) 中,所以 Mike 其实只能在斜率为 -1 的直线上走动;

又由于硬币数量不为负数,Mike 可以以任意点为起点,只要不走重复路即可,所以可以确定 Mike 从每条斜线的左上方走到右下方(或右下方走到左上方)所能收获的硬币是该条路径上收获最多的方案;

所以只要对比 2 * n - 1 条斜线中收获硬币数最大的一条即可;

而在一条斜线上的点 (i-1,j-1),(i,j),(i+1,j+1)来说,其纵坐标与横坐标的差为确定的 j - i;

但对于第一列来说 j - i 是个负数,所以需要整体加上 n - 1 (存在 n - 1 个负数);

所以在读入(i, j) 位置的硬币数的同时,也可以计算当前第 j - i + n - 1 条斜线上的最大的硬币数;

最后遍历每条斜线求出最大的硬币数即可。

注意:结果会很大,记得开 long!(每天在数据范围栽一次的我)

AC代码

Java

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.StringTokenizer;

public class Main {
	
	public static void main(String[] args) throws IOException {
		InputReader in = new InputReader(System.in);
		PrintWriter out = new PrintWriter(System.out);
		
		int t = in.nextInt();
		
		int n = 0;
		long[] c;
		
		long res = -1;
		int a = 0;
		
		for(int i = 1; i <= t; i++) {
			n = in.nextInt();
			
			c = new long[2 * n - 1];
			
			for(int j = 0; j < n; j++) {
				for(int k = 0; k < n; k++) {
					a = in.nextInt();
					c[k - j + n - 1] += a;
				}
			}
			
			res = -1;
			for(int j = 0; j < 2 * n - 1; j++) {
				res = Math.max(res, c[j]);
			}
			
			out.println("Case #" + i + ": " + res);
		}
		
		out.flush();
	}
	
	public static class InputReader {
		BufferedReader reader;
		StringTokenizer tokenizer;
		
		public InputReader(InputStream in) {
			reader = new BufferedReader(new InputStreamReader(in));
		}
		
		public String next() throws IOException {
			while(tokenizer == null || !tokenizer.hasMoreTokens()) {
				tokenizer = new StringTokenizer(reader.readLine());
			}
			return tokenizer.nextToken();
		}
		
		public int nextInt() throws IOException {
			return Integer.parseInt(next());
		}
	}

}

c++

#include<bits/stdc++.h>

using namespace std;

const int N = 2010;

int main()
{
    int t = 0;
    scanf("%d", &t);

    int n = 0;
    long c[N];

    int a = 0;
    long res = -1;

    for(int i = 1; i <= t; i++)
    {
        scanf("%d", &n);
        memset(c, 0, sizeof(c));

        for(int j = 0; j < n; j++)
        {
            for(int k = 0; k < n; k++)
            {
                scanf("%d", &a);
                c[k - j + n - 1] += a;
            }
        }

        res = -1;
        for(int j = 0; j < 2 * n - 1; j++) res = max(res, c[j]);

        printf("Case #%d: %ld\n", i, res);
    }

    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值