【问题标题】:Find path of FIXED length through a 2D array which gives maximum sum通过二维数组查找固定长度的路径,该数组给出最大和
【发布时间】:2014-12-20 04:37:42
【问题描述】:

我查看了许多与此问题类似的论坛代码,但我仍然无法解决我的问题。基本上,给定一个大小为 n 的二维方阵,填充 [-100,100] 内的整数,我必须找到最大和,因为路径的长度为 10。这是从某个给定的网格开始完成的(用 * 表示)。两次访问同一个网格是违法的。

一个示例测试用例是:

-55  34 -51  35  1
-76  26  69  61  *
 68  98  17  85  81
-27 -69  49  42  83
-10  31  44  75 -41

将产生637 的最大总和。 用路径表示:61 69 26 98 17 85 81 83 42 75

如果我没记错的话,我的代码的问题是关于标记我之前访问过的网格。但我不知道如何解决..

下面是我的代码:

import java.util.*;

class Maze
{
static int[][] matrix;
static int counter = 0;
static int size = 0;
static int maximum = -100000;
static int result = -1000000;
static int currMax; 
static int topMax, downMax, leftMax, rightMax;

public static void main(String [] args)
{
    Scanner sc = new Scanner(System.in);
    size = sc.nextInt();
    matrix = new int[size][size];
    int xcord = 0;
    int ycord = 0;
    for (int i=0; i<size; i++){
        for (int j=0; j<size; j++){
            if (sc.hasNextInt()){
                int util = sc.nextInt();
                matrix[i][j] = util;
            }
            else{
                String utilStr = sc.next();
                xcord = i;
                ycord = j;
                matrix[i][j] = -2000;
            }
        }
    }
    result = 2000 + findMax(xcord, ycord);
    System.out.println(result);
}

static int findMax(int currx, int curry){
    if (counter >= 9){
            return matrix[currx][curry];
    }
    else {
        counter = counter+1;

        System.out.println("Round: "+counter);
        System.out.println("currx: "+currx+" curry: "+curry);
        int temp = matrix[currx][curry];
        matrix[currx][curry] = -2000;

        downMax = -10000; //To reset it for comparison
        if (currx+1 != size && matrix[currx+1][curry] == -2000){
        downMax = findMax(currx+1,curry);
        }
        rightMax = -10000;
        if (curry+1 != size && matrix[currx][curry+1] == -2000){
        rightMax =  findMax(currx,curry+1);
        }
        topMax = -10000;
        if (currx-1 >=0 && matrix[currx-1][curry] == -2000){
        topMax =  findMax(currx-1,curry);
        }
        leftMax = -10000;
        if (curry-1 >= 0 && matrix[currx][curry-1] == -2000){
        leftMax =  findMax(currx,curry-1);
        }

        matrix[currx][curry] = temp;

        currMax = Math.max(downMax,rightMax);
        currMax = Math.max(currMax, topMax);
        currMax = Math.max(currMax, leftMax);

        maximum = currMax + temp;
        return maximum;
        }
}

}

提前致谢!!

【问题讨论】:

  • 这里有一些提示:你没有做任何事情来标记你已经访问过的地方。如果你这样做,它也将帮助你摆脱相当随意的“2000”标志。此外,您永远不会增加counter,因此一旦完成一次遍历,它就会保持在 9。我建议将当前深度作为参数而不是静态字段传递。
  • 感谢您的回复!在将深度作为参数传递后,我设法完成了递归。但是,我对已访问网格的标记仍然不起作用。我使用 matrix[currx][curry] = -5000 来标记我已经通过的节点,然后将值设置回来。为什么它不起作用?
  • 这不是因为有许多可能的路径可能会给你想要的答案,但是当你用 -5000 标记一个字段时,这个单元格会被所有其他潜在路径污染。
  • 哦,但是我正在使用 matrix[currx][curry] = temp 在同一个递归中将值改回,所以不会恢复该值(从而再次打开路径?)。抱歉,我不太明白。关于如何标记路径的任何建议?
  • 你在所有的递归之后把它改回来。所以所有更深的递归级别仍然看到标志。

标签: java recursion path multidimensional-array maze


【解决方案1】:

这是我的解决方案和解释:

public static int MAX_DEPTH = 10;

static Integer[][] matrix;
static Coord[] directions = {
    new Coord(-1, 0),
    new Coord(1, 0),
    new Coord(0, -1),
    new Coord(0, 1)
};

private static class Coord {
    int row;
    int col;

    private Coord(int row, int col) {
        this.col = col;
        this.row = row;
    }

    private Coord newPosition(Coord relative) {
        return new Coord(row + relative.row, col + relative.col);
    }
}

首先,我将矩阵定义为Integer 的二维数组,而不是int。这使得使用null 标记访问位置和“*”位置变得容易。这只是一种方便。

我正在使用一个小的内部类Coord 来帮助我进行坐标计算。如您所见,我创建了一个静态数组,其中包含我在每一步都需要探索的所有方向,因为这将简化递归方法,并防止不必要的代码重复,这些代码以后可能需要在四个不同的地方修复。

private static Coord fillMatrix() {
    Scanner sc = new Scanner(System.in);
    int size = sc.nextInt();
    matrix = new Integer[size][size];
    Coord coord = new Coord(0, 0);
    for (int i = 0; i < size; i++) {
        for (int j = 0; j < size; j++) {
            if (sc.hasNextInt()) {
                int util = sc.nextInt();
                matrix[i][j] = util;
            } else {
                sc.next();
                coord.row = i;
                coord.col = j;
                matrix[i][j] = null;
            }
        }
    }
    sc.close();
    return coord;
}

我的fillMatrix 方法填充矩阵并返回“*”的坐标(或者更确切地说,输入中的非整数)。它基于您的,并附有以下注释:

  • 我将矩阵中的“*”位置标记为空。
  • 您应该关闭您打开的每个扫描程序。
  • 没有必要定义一个变量来存储扫描“*”的值,因为我们不使用它。 Java 允许调用返回值的方法,而无需在任何地方分配该值。
    private static boolean isLegalPosition(Coord position) {

        if ( position.row < 0 || position.row >= matrix.length ) {
            return false;
        }

        if ( position.col < 0 || position.col &gt= matrix[0].length ) {
            return false;
        }

        return matrix[position.row][position.col] != null;
    }

给定矩阵中的一个位置,此方法检查它是否合法——它是否在数组的边界内(我们必须假设至少存在一行),以及它是否没有用null 标记(已访问/开始)。

现在我们来看看递归方法本身。您将当前深度和当前累积总和传递给它,当然,还传递给它应该开始查找的当前位置。假定此位置已被标记为 null。


    private static Integer findMax(Coord currPosition, int currDepth,
            int currSum) {

        // Recursion end: if we reached a depth of 10, we have the maximum at
        // the current position

        if (currDepth == MAX_DEPTH) {
            return currSum;
        }

        // Find the greatest number in all four directions. We start with an
        // unknown Max value.

        Integer currMax = null;
        for (Coord direction : directions) {

            Coord newPos = currPosition.newPosition(direction);

            // If the position is legal (inside the matrix and not visited),
            // explore it by adding depth, and adding the current matrix
            // value to the accumulated.
            if (isLegalPosition(newPos)) {

                // Save the value at the new position, and mark it as visited.
                int matrixValue = matrix[newPos.row][newPos.col];
                matrix[newPos.row][newPos.col] = null;

                Integer newMax = findMax(newPos, currDepth + 1, currSum + matrixValue);

                // Restore the value in the current matrix position so that
                // upper level recursions don't think it's visited.
                matrix[newPos.row][newPos.col] = matrixValue;

                // Calculate the new max. If this is the first legal path, use
                // it. Otherwise check which one is greater.
                if (newMax != null) {
                    currMax = (currMax == null) ? newMax
                            : (newMax > currMax ? newMax : currMax);
                }
            }
        }

        return currMax;
    }

如您所见,我保留了一个名为currMax 的变量,它以null 开头。它将最终成为从四个方向收集的所有数字中的最大值。但可能会发生所有四个方向都无法达到深度 10,因为它们会撞到墙壁并访问过位置。在这种情况下,它们将返回 null,如果这发生在所有四个方向上,我们也会返回 currMax - 即 null

如果我们确实在任何方向上找到了合法路径,我们将使用它更新currMax(当然,如果它大于它)。

在每个步骤中,在我们深入递归之前,我们用 null 标记新位置以表明它已被访问,但请注意在完成后立即恢复它。否则,该位置将保持标记为下一个方向的访问,它不应该被视为visited

main调用递归,填充矩阵后,当然是这样的:

Integer maxVal = findMax(startCoord, 0, 0);

也就是说,我们将“*”的坐标传递给它,从深度 0 开始,累积和为 0。为什么是 0 而不是 -2000?因为我们实际上并没有将这个数字与任何东西进行比较。我们经过的任何实际到达深度 10 的路径都将返回它经过的位置的实际总和,加上这个零,无论这个总和是负数还是正数。任何未到达深度 10 的路径都将返回 null。所以不需要人为的值。

【讨论】:

  • 谢谢你超级详细的解释!我设法解决了这个问题。
  • +1 用于紧凑性和较小的内存占用。我猜 isLegalPosition() 中的条件应该是 if (position.row == matrix.length || position.row
  • @Oncaphillis 哦,显然当使用
     作为代码格式时,需要转义“
                    
                  
                    
                
【解决方案2】:

这个怎么样。当前搜索路径存储在 Stack 容器中,有助于识别我们已经看到的位置。在每个递归级别上,我们都会查看当前位置的字段 S/N/W/E,如果当前堆栈大小 == 11(起始字段加上其余部分),则将 currMax 设置为当前总和。

import java.util.*;
import java.io.*;



class Coord {
    public Coord(int i,int j) {
        this.i=i;
        this.j=j;
    }
    public boolean equals(Object o) {
        return ((Coord)o).i == i && ((Coord)o).j == j;
    }

    public int i;
    public int j;
};

class Main {
    static int[][] matrix;
    static int counter = 0;
    static int size = 0;
    static int currMax=-2000; 
    static Stack<Coord> currStack = new Stack<Coord>();


    public static void main(String [] args) throws FileNotFoundException
    {
        FileInputStream f=new FileInputStream(new File("/home/bla/bla.txt"));
        Stack<Coord> s = new Stack<Coord> ();

        Scanner sc = new Scanner(f);
        size = sc.nextInt();

        matrix = new int[size][size];
        int xcord = 0;
        int ycord = 0;
        for (int i=0; i<size; i++){
            for (int j=0; j<size; j++){
                if (sc.hasNextInt()){
                    int util = sc.nextInt();
                    matrix[i][j] = util;
                }
                else{
                    String utilStr = sc.next();
                    s.push(new Coord(i,j));
                }
            }
        }

        int sum=0;
        System.out.println(findMax(s,sum));

        Iterator<Coord> i=currStack.iterator();
        int ss=0;
        while(i.hasNext()) {
            Coord c = i.next();
            System.out.println(c.i+" "+c.j+" "+matrix[c.i][c.j]);
            ss+=matrix[c.i][c.j];

        }
        System.out.println("<"+ss+">");

    }

    static int findMax(Stack<Coord> s,int sum){

        // TOP
        if(s.lastElement().i > 0    && (s.search(new Coord(s.lastElement().i-1,s.lastElement().j  ))==-1) ) {
            Stack<Coord> nstack = (Stack<Coord>)s.clone();
            nstack.push(new Coord(s.lastElement().i-1,s.lastElement().j  ));
            int nsum = sum + matrix[nstack.lastElement().i][nstack.lastElement().j];
            if(nstack.size()<11) {
                nsum=findMax(nstack,nsum);
            }
            else {
                if(nsum > currMax) {
                    currMax   = nsum;
                    currStack = nstack;
                }
            }
        }
        // BOTTOM
        if(s.lastElement().i+1 < matrix.length && (s.search(new Coord(s.lastElement().i+1,s.lastElement().j  ))==-1) ) {
            Stack<Coord> nstack = (Stack<Coord>)s.clone();
            nstack.push(new Coord(s.lastElement().i+1,s.lastElement().j  ));            
            int nsum = sum + matrix[nstack.lastElement().i][nstack.lastElement().j];
            if(nstack.size()<11) {
                nsum = findMax(nstack,nsum);
            }
            else {
                if(nsum>currMax) {
                    currMax   = nsum;
                    currStack = nstack;
                }
            }
        }
        // LEFT
        if(s.lastElement().j > 0   && (s.search(new Coord(s.lastElement().i  ,s.lastElement().j-1))==-1) ) {
            Stack<Coord> nstack = (Stack<Coord>)s.clone();
            nstack.push(new Coord(s.lastElement().i  ,s.lastElement().j-1));
            int nsum = sum + matrix[nstack.lastElement().i][nstack.lastElement().j];
            if(nstack.size()<11) {
                nsum = findMax(nstack,nsum);
            }
            else {
                if(nsum>currMax) {
                    currMax   = nsum;
                    currStack = nstack;
                }
            }
        }

        // RIGHT
        if(s.lastElement().j+1 < matrix[0].length && (s.search(new Coord(s.lastElement().i  ,s.lastElement().j+1))==-1) ) {
            Stack<Coord> nstack = (Stack<Coord>)s.clone();
            nstack.push(new Coord(s.lastElement().i  ,s.lastElement().j+1));
            int nsum = sum +matrix[nstack.lastElement().i][nstack.lastElement().j];
            if(nstack.size()<11) {
                nsum = findMax(nstack,nsum);
            }
            else {
                if(nsum>currMax) {
                    currMax   = nsum;
                    currStack = nstack;
                }
            }
        }
        return currMax;
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-08-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-29
    • 2020-03-19
    相关资源
    最近更新 更多