我遇到了这个问题。
让我们考虑一个游戏,它有3个单元格宽的单元格 N 单元格。每个细胞都有一个 写在0和99之间的数字。你可以进入任何一个董事会 顶行的单元格,从底部的任何单元格退出。您 可以从一个单元格移动到下面一行中的任何相邻单元格(对角线或正下方)。 当您在单元格时,您必须添加或减去写入的数字 在细胞上。 对于给定值X,大于或等于的最小数量是多少 X,你可以从这个过程获得吗?
输入 第一行输入包含一个整数,即数字 测试用例。每个测试用例的第一行包含两个整数, N 和 X 。 下一个 N 行每个包含三行 以空格分隔的数字,必须添加或减去的单元格值。
输出
对于每组输入打印,最小数字大于或等于 X
示例输入
2
3 0
83 86 77
15 93 35
86 92 49
3 59
83 86 77
15 93 35
86 92 49
示例输出
2 59
注意:
2 = 86 - 35 - 49
59 = 86 - 93 + 86
这是我的解决方案:
import java.util.Scanner;
public class n3 {
static int min;
static int result;
static int X;
int go = 0;
public static void main(String args[]) throws Exception {
{
Scanner sc = new Scanner(System.in);
// sc = new Scanner(new FileInputStream("input.txt"));
int T = sc.nextInt();
for (int tc = 0; tc < T; tc++) {
int N = sc.nextInt();
min = sc.nextInt();
result = Integer.MAX_VALUE;
int m[][] = new int[N][N];
for (int i = 0; i < N; i++) {
for (int j = 0; j < 3; j++) {
m[i][j] = sc.nextInt();
}
}
n3 game = new n3();
game.start(m, N);
System.out.println(result);
}
}
}
private void start(int[][] m, int N) {
int x = min;
compute(m, -1, 0, 0, N);
// compute(m, -1, 0, -x, N);
compute(m, -1, 1, 0, N);
compute(m, -1, 2, 0, N);
}
private boolean isSafe(int[][] m, int row, int col, int N) {
if (row >= 0 && col >= 0 && row < N && col < 3) {
return true;
}
return false;
}
private void compute(int[][] m, int x, int y, int value, int N) {
// System.out.println(value + " " + x + " " + y);
if (go == 1) {
return;
}
if (x == N - 1 && value >= min) {
if (value < result) {
result = value;
}
if (value == min) {
result = min;
go = 1;
}
return;
}
if (isSafe(m, x + 1, y - 1, N)) {
compute(m, x + 1, y - 1, value + m[x + 1][y - 1], N);
compute(m, x + 1, y - 1, value - m[x + 1][y - 1], N);
}
if (isSafe(m, x + 1, y, N)) {
compute(m, x + 1, y, value + m[x + 1][y], N);
compute(m, x + 1, y, value - m[x + 1][y], N);
}
if (isSafe(m, x + 1, y + 1, N)) {
compute(m, x + 1, y + 1, value + m[x + 1][y + 1], N);
compute(m, x + 1, y + 1, value - m[x + 1][y + 1], N);
}
}
}
然而,当N很大时,这会失败。还有其他方法可以解决这个问题吗?
答案 0 :(得分:2)
每次调用compute(m,x,...)都会进行四次或六次计算调用(m,x + 1,...)。因此,如果将N增加1,则工作量至少增加4倍。您的代码将永远运行。
对于每一行和每列,都要跟踪您在该点可能具有的整数集。然后在递归中,检查您是否已经计算了该行/列的点,而不是再次计算。
答案 1 :(得分:0)
@ gnasher729有正确的想法。以下是您给出的示例的简短描述。
从电路板顶部开始。对于每个方格,移动并计算每个方格的可能总数。将这些填入列表清单;这一行的“状态”看起来像是:
left: [-83, 83],
mid: [-86, 86],
right: [-77, 77]
现在移动到第2行。中间位置可以连接到3个方块中的每一个;两端只能连接到较近的地方2.使用add&amp;减去每个正方形的运算。例如,左方(15)可以由左(83)或中(86)位置“馈送”。这一次,我将分两步完成:
left: [-83-15, 83-15, -83+15, 83+15, -86-15, 86-15, -86+15, 86+15],
mid: [-83-93, 83-93, -83+93, 83+93, -86-93, 86-93, -86+93, 86+93, -77-93, 77-93, -77+93, 77+93]
right: [-86-35, 86-35, -86+35, 86+35, -77-35, 77-35, -77+35, 77+35]
当我们进行数学计算时,我们得到条目:
[-98, 68, -68, 98, -101, 71, -71, 101],
[-176, -10, 10, 176, -179, -7, 7, 179, -170, -16, 16, 170],
[-121, 51, -51, 121, -112, 42, -42, 112]
继续沿着桌子的行向前走。由于您不关心路径,只关注总和本身,您不必跟踪所有小计 - 只是最近一行的左,中,右集。
当你到达底部时,合并三个列表,按升序排序,然后取第一个至少与 X 一样大的数字。