题目
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;
}