4X4矩阵中长度为5的所有可能的组合

时间:2010-12-02 20:25:31

标签: python recursion combinatorics

我有一个矩阵

1 9 2 3
5 0 0 6
8 4 4 8
2 3 7 8

我需要找到所有可能的长度为5的数字组合。

约束:

  1. 从矩阵中的任何位置开始,你只能移动到你的下一个直接邻居,即如果你开始形式说(0,0)你的邻居必须是(0,1),(1,1), (1,0)如果您选择一个位置然后形成该位置,您只能移动到其直接邻居,依此类推。

  2. 数字的长度必须是5位数,即例如,如果我从(0,0)开始,值为1,我可以产生序列15151或19232或10063,所以你可以按任何顺序移动约束1适用。

  3. 解决方案必须在7秒内产生输出,而python是我最喜欢的首选。 ;)

  4. 好的我错过了一些程序必须使用所有16​​个数字的东西,即它必须使用所有16​​个数字作为初始并产生5位数序列。

5 个答案:

答案 0 :(得分:2)

这是Scala中的解决方案(对于5x5版本,9位数字,从中间开始)(带有ideone.com demo)。在我的(相当慢的)计算机上执行需要5秒钟。

object Main {

    val matrix = List(List("1", "9", "2", "3", "1"),
                      List("5", "0", "0", "6", "1"),
                      List("8", "4", "4", "8", "1"),
                      List("8", "4", "4", "8", "1"),
                      List("2", "3", "7", "8", "1"))

    def main(args: Array[String]) : Unit = nums(2, 2, 9) map println

    def nums(r: Int, c: Int, left: Int) : List[String] =
        if (!(matrix isDefinedAt r) || !(matrix(r) isDefinedAt c)) List()
        else if (left == 0) List("")
        else for ((dr, dc) <- List((0,1), (1,0), (-1,0), (0,-1));
                  tail <- nums(r + dr, c + dc, left - 1))
                yield matrix(r)(c) + tail
}

这是Java中的解决方案(带有ideone.com demo)。

import java.util.*;

public class Test {

    static String[][] matrix = {{"1", "9", "2", "3"},
                                {"5", "0", "0", "6"},
                                {"8", "4", "4", "8"},
                                {"2", "3", "7", "8"}};

    public static void main(String[] args) {
        for (String i : nums(0, 0, 5))
            System.out.println(i);
    }

    public static List<String> nums(int r, int c, int left) {

        if (r < 0 || r >= matrix.length || c < 0 || c >= matrix[r].length)
            return Collections.emptyList();

        if (left == 1)
            return java.util.Arrays.asList(matrix[r][c]);

        ArrayList<String> result = new ArrayList<String>();
        for (int[] delta : new int[][] {{0,1}, {1,0}, {-1,0}, {0,-1}})
            for (String tail : nums(r + delta[0], c + delta[1], left-1))
                result.add(matrix[r][c] + tail);

        return result;
    }
}

我的电脑上执行了8毫秒。


如果你想加快速度,你一定要缓存结果。有两种方法可以让两个步骤向下,两个步骤向右移动,使用4个数字。所有这些都将共享相同的尾部(即nums(row + 2, col + 2, x))。

答案 1 :(得分:0)

你可以通过递归和回溯来轻松地写这个。

具有递归功能:

FOO(X,Y,深度)

然后递归尝试移动每个方向,这是有效的。达到最大深度(5)时,您有一个数字。然后,它只是用于构建和组合列表的簿记。

修改

多一点信息..

foo( x, y, depth, seq )

其中seq是到此为止的序列的字符串。它返回一个字符串列表,它们是解决方案。

基本情况:深度为5,在这种情况下只返回一个列表,其中当前数字连接到seq。

否则检查每个方向的边界,如果有效,请使用正确的坐标,深度+1和连接到seq的当前数字调用foo。将所有结果列表组合在一起并返回。

为每个初始点调用此函数,深度为1,序列为“”,然后将所有这16个结果组合在一起。

请注意,因为这是递归的,所以对于这个问题大小可以正常工作,但是可以很快地变慢。虽然因为它受到深度限制,但我不认为它会成为一个问题。

1503 独特的解决方案

修改2

我的搜索功能与您的搜索功能非常相似,但请查看正在检查的边界以及返回的值等。

def foo(x,y,depth,seq):
    if depth == 5: return [seq + str(matrix[x][y])]

    cur = []
    seq = seq + str(matrix[x][y])
    if (y - 1) >= 0: cur.extend(search(x,y-1,depth+1,seq))
    if (x + 1) < len(matrix[0]): cur.extend(search(x+1,y,depth+1,seq))
    if (y + 1) < len(matrix): cur.extend(search(x,y+1,depth+1,seq))
    if (x - 1) >= 0: cur.extend(search(x-1,y,depth+1,seq))

    return cur  

我检查四个方向的方式可以被清理掉并且更加“pythonic”,但这更像是一个概念验证,你可以足够快地解决问题。

答案 2 :(得分:0)

查看itertools组合生成器获取灵感:

  • 产物()
  • permutations()
  • 组合()
  • combinations_with_replacement()

答案 3 :(得分:0)

修改     def foo(x,y,depth,seq):

def search(x,y,depth,seq):

if depth == 8: 

    return [seq + str(matrix[x][y])]

cur = []

seq = seq + str(matrix[x][y])

if (y - 1) >= 0: 

    cur.extend(search(x,y-1,depth+1,seq))

if (x + 1) < len(matrix[0]): 

    cur.extend(search(x+1,y,depth+1,seq))

if (y + 1) < len(matrix): 

    cur.extend(search(x,y+1,depth+1,seq))

if (x - 1) >= 0: 

    cur.extend(search(x-1,y,depth+1,seq))

if (x + 1) < len(matrix[0]) and (y + 1) < len(matrix): 

    cur.extend(search(x+1,y+1,depth+1,seq))

if (x - 1) >= 0 and (y - 1) >=0: 

    cur.extend(search(x-1,y-1,depth+1,seq))

if (x + 1) < len(matrix[0]) and (y - 1) >= 0: 

    cur.extend(search(x+1,y-1,depth+1,seq))

if (x - 1) >= 0 and (y + 1) < len(matrix): 

    cur.extend(search(x-1,y+1,depth+1,seq))

return cur

matrix = [[1,1,2,3,5],

    [2,3,4,5,5],

    [5,5,2,3,3],

    [9,9,5,4,2],

    [9,9,5,4,2],

    ]

如果名称 ==“主要”:

print search(0,0,0,"")

我跑了这段代码花了19~20秒才停下来。这也只是一个初始位置,也产生了很多重复的结果。我在2.2Ghz core 2 duo处理器上运行了这个,我的旧电脑挂了,python.exe崩溃了:p。

答案 4 :(得分:0)

首先,您必须考虑如何从矩阵中的一个位置开始并移动到相邻位置。

蛮力方法只是列出所有可用的单元格和每个单元格的所有相邻单元格:

nextpos = {
    (0,0): [(1,0), (1,1), (0,1)],
    (0,1): [(0,0), (1,0), (1,1), (1,2), (0,2)],
    (0,2): [(0,1), (1,1), (1,2), (1,3), (0,3)],
    (0,3): [(0,2), (1,2), (1,3)],
    # etc
}
allpos = nextpos.keys()

对于这个小问题,这很简单;然而,总有可能出现错别字。另一种解决方案是编写生成器函数:

def nextpos(p,w=4,h=4):
    """
    @param p     Current position tuple (x,y)
    @param w     Width of matrix
    @param h     Height of matrix

    Generate all matrix cells adjacent to the current one
    """
    rel = ((-1,0),(-1,1),(0,1),(1,1),(1,0),(1,-1),(0,-1),(-1,-1))

    x,y = p
    for dx,dy in rel:
        nx,ny = x+dx, y+dy
        if 0<=nx<w and 0<=ny<h:
            yield (nx,ny)

一旦我们知道哪些单元格彼此相邻,我们就可以继续寻找有效的路径:

def matrix_path(pathLen, startFrom=None):
    """
    @param pathLen    Length of path to return
    @param startFrom  Initial location

    Generate all adjacency paths through the matrix
    """

    # bad path length - quit gracefully
    if pathLen<1:
        yield []
        return

    # no starting point specified - start at any point
    if startFrom is None:
        for pos in allpos:
            for res in matrix_path(pathLen, pos):
                yield res
        return

    # end of path
    if pathLen==1:
        yield [startFrom]
        return

    # from current point, recurse to find rest of path
    for pos in nextpos[startFrom]:
        for morePath in matrix_path(pathLen-1, pos):
            yield [startFrom]+morePath

我们可以通过分析找出这需要多长时间:

import cProfile

def test():
    sols = [i for i in matrix_path(5)]
    print len(sols), "paths found"

cProfile.run("test()")

返回

  找到16860条路径            121497函数调用(16865基元调用),0.678 CPU秒

这将返回一个单元格位置列表;我们想把它变成矩阵的实际值,

def path_vals(mx, path):
    """
    @param mx    Matrix data
    @param path  List of cell positions

    Return list of values from list of cell positions
    """

    return tuple([mx[x][y] for x,y in path])

然后

mx = [
    [1,9,2,3],
    [5,0,0,6],
    [8,4,4,8],
    [2,3,7,8]
]

def test():
    sols = [path_vals(mx, i) for i in matrix_path(5)]

我们还希望将列表缩小为唯一结果:

def test():
    usol = list(set([path_vals(mx, i) for i in matrix_path(5)]))
    print len(usol),"unique results"

cProfile.run("test()")

给了我们

  

8651个独特的结果            138357函数调用(33725原始调用),在0.845 CPU秒内