矩阵中的数字

时间:2015-10-03 23:48:11

标签: python matrix

我试图用Python解决以下问题:

enter image description here

但是我被困在生成一个有效的表。我希望程序显示一个有效的矩阵,但为了让程序继续而不打印None,我必须为没有可能的正方形分配7。应该修复什么?

到目前为止我的代码:

from pprint import pprint
import sys
import random

sys.setrecursionlimit(10000)

def getPossiblesForSquare(sqx,sqy,matrix):
    '''Gets the possible entries of matrix[sqy][sqx].
Assumes it equals 0.'''
    assert matrix[sqy][sqx]==0
    # get the row that it is on
    rowon=matrix[sqy]
    # columns are a little trickier
    colon=[matrix[row][sqx] for row in range(5)]

    # find the possibilities!
    possibles=list(range(1,7))

    for item in list(set(rowon+colon)): # remove duplicates
        if not (item == 0) and (item in possibles):
            del possibles[possibles.index(item)]

    random.shuffle(possibles)

    return possibles

def getPossiblesForMatrix(matrix):
    '''Gets all the possible squares for a matrix.'''
    possiblesdict={}
    for y in range(6):
        for x in range(6):
            if matrix[y][x]==0:
                possiblesdict[(y,x)]=getPossiblesForSquare(x,y,MATRIX)
    return possiblesdict

def flattenList(matrix):
    result=[]
    for i in matrix:
        if not isinstance(i,list):
            result+=[i]
        else:
            result+=flattenList(i)
    return result

def getPossibleMatrix(startMatrix, iteration=0, yon=1, prevZeroInd=None):
    if 0 not in flattenList(startMatrix):
        print('RESULT:\n\n')
        return startMatrix
    else:
        # find&fill in the first blank one
        ind=flattenList(startMatrix).index(0)
        y=ind//6
        x=ind%6
        if (x,y)==prevZeroInd:
            startMatrix[y][x]=7
        else:
            possibles=getPossiblesForSquare(x,y,startMatrix)
            if len(possibles)==0:
                startMatrix[y][x]=7
            else:
                startMatrix[y][x]=possibles[0]
            if iteration <= 6:
                return getPossibleMatrix(startMatrix, iteration+1, yon, (x,y)) # <<BUG
            else:
                if yon!=4:
                    return getPossibleMatrix(startMatrix, 0, yon+1, (x,y))


MATRIX=[[1,2,3,4,5,6],
        [2,0,0,0,0,5],
        [3,0,0,0,0,4],
        [4,0,0,0,0,3],
        [5,0,0,0,0,2],
        [6,5,4,3,2,1]]

result=getPossibleMatrix(MATRIX)
pprint(result)

2 个答案:

答案 0 :(得分:3)

为什么你的脚本会挂起:

基本上你的脚本在这里遇到问题:

for item in list(set(rowon + colon)):  # remove duplicates
    if not (item == 0) and (item in possibles):
        del possibles[possibles.index(item)]
  • 在第三次迭代中,对于第三个单元格,对于所有可能的值[1 to 6],if条件被评估为true(如果输出矩阵,您将看到正在创建的set()包含所有元素),所以你总是返回零,重新检查值,返回零ad infinitum

如果您正在寻找强制解决此问题的解决方案,您可能需要更新sqxsqy,以便在可能为空时转到其他单元格。

我找到的另一个小错误是:

# you are checking values 1-5 and not 1-6!
possibles = list(range(1, 6)) # should be range(7) [exclusive range] 
  • 不要忘记该范围是独家的,它不包括(排除)上限。

当然,存在解决此问题的不同方法。

可能的替代解决方案:

  

阅读本文,了解如何解决此问题的一般替代视图。如果您不想看到可能的解决方案,请跳过&#39;代码&#39;一部分。

解决方案矩阵(可能的一个)有这种形式(除非我犯了一个可怕的错误):

MATRIX = [[1, 2, 3, 4, 5, 6],
          [2, 3, 6, 1, 4, 5],
          [3, 1, 5, 2, 6, 4],
          [4, 6, 2, 5, 1, 3],
          [5, 4, 1, 6, 3, 2],
          [6, 5, 4, 3, 2, 1]]

逻辑如下:

您必须观察矩阵中存在的对称性。具体来说,每一行和每一列都会显示“翻转和反转”字样。对称。例如,第一行和最后一行通过以下等式连接:

row[0] = REV(flip(row[n]))

同样,所有其他行(或列)都有相应的对应部分:

row[1] = REV(flip(row[n-1]))

等等。

所以,对于n=6,这基本上归结为找到(n / 2) -1(因为我们已经知道了第一行和最后一行!)然后翻转它们(而不是手指),将它们反转并分配它们到他们相应的行。

为了找到这些值,我们可以将矩阵视为较小矩阵的组合:

这些是矩阵的前两行(未知):

sub_matrix = [[1, 2, 3, 4, 5, 6],
              [2, 0, 0, 0, 0, 5],
              [3, 0, 0, 0, 0, 4],
              [6, 5, 4, 3, 2, 1]]

可以通过为这两个行找到正确的值来制作另外两行。

遵守手头的限制:

[1][1]栏和[1][m-1]栏中,我们不能:

  • 放置25

[1][2][1][m-2]列中,我们不能:

  • 将之前的值([2, 5])与([3, 4])放在一起,这样我们就无法获得值in [2,3,4,5]

对于内部列,我们留下了set(1-6) - set(2-5) = [1, 6]集 因为我们得到一个正常的行和一个 反转和翻转的行,我们可以任意选择一个值并将其添加为列值。

通过使用另一个列表,我们可以跟踪使用的值并填写剩余的单元格。

编码:(剧透)

注意:我没有使用numpy。您可以应该。 (另外,Python 2.7

另外,我没有使用递归(你可以尝试通过为更大的n值找到相同的矩阵[我相信它非常适合递归函数]。

首先,为了不一直打字,你可以按如下方式创建一个n x n矩阵:(这不是一个剧透。)

# our matrix must be n x n with n even.
n = 6

# Create n x n matrix.
head = [i for i in xrange(1, n + 1)]   # contains values from 1 to n.
zeros = [0 for i in xrange(1, n-1)]    # zeros
tail = [i for i in xrange(n, 0, -1)]   # contains values from n to 1.


# Add head and zeros until tail.
MATRIX = [([j] + zeros + [(n+1)-j]) if j != 1 else head for j in xrange(1, n)]
# Add tail
MATRIX.append(tail)

然后,创建较小的(n/2 + 1) x n数组:

# Split matrix and add last row.
sub_matrix = MATRIX[:(n / 2)] + [tail]

之后,一个名为sub = fill_rows(sub_matrix)的小功能进来并负责业务:

def fill_rows(mtrx):

    # length of the sub array (= 4)
    sub_n = len(mtrx)

    # From 1 because 0 = head
    # Until sub_n -1 because the sub_n - 1 is = tail (remember, range is exclusive)
    for current_row in xrange(1, sub_n - 1):
        print "Current row: " + str(current_row)

        # -- it gets messy here --
        # get values of inner columns and filter out the zeros (matrix[row][n / 2] == 0 evaluates to False)
        col_vals_1 = [mtrx[row][n / 2] for row in xrange(0, sub_n) if mtrx[row][(n / 2)]]
        col_vals_2 = [mtrx[row][(n / 2) - 1] for row in xrange(0, sub_n) if mtrx[row][(n / 2) - 1]]

        col_vals = col_vals_1 + col_vals_2
        # print "Column Values = " + str(col_vals)

        row_vals = [mtrx[current_row][col] for col in xrange(0, n) if mtrx[current_row][col]]
        # print "Row Values = " + str(row_vals)

        # Find the possible values by getting the difference of the joined set of column + row values
        # with the range from (1 - 6).
        possible_values = list(set(xrange(1, n + 1)) - set(row_vals + col_vals))

        print "Possible acceptable values: " + str(possible_values)

        # Add values to matrix (pop to remove them)
        # After removing add to the list of row_values in order to check for the other columns.
        mtrx[current_row][(n-1)/2] = possible_values.pop()
        row_vals.append(mtrx[current_row][(n - 1) / 2])
        mtrx[current_row][(n-1)/2 + 1] = possible_values.pop()
        row_vals.append(mtrx[current_row][(n-1) / 2 + 1])

        # New possible values for remaining columns of the current row.
        possible_values = list(set(xrange(1, n + 1)) - set(row_vals))
        print "Possible acceptable values: " + str(possible_values)

        # Add values to the cells.
        mtrx[current_row][(n - 2)] = possible_values.pop()
        mtrx[current_row][1] = possible_values.pop()

    # return updated sub-matrix.
    return mtrx

现在唯一要做的就是拍摄这两行,翻转它们,反转它们并添加头部和尾部:

print '=' * 30 + " Out " + "=" * 30

# Remove first and last rows.
del sub[0]
sub.pop()

# reverse values in lists
temp_sub = [l[::-1] for l in sub]
# reverse lists in matrix.
temp_sub.reverse()

# Add them and Print.
pprint([head] + sub + temp_sub + [tail])

我希望这是正确的矩阵:

============================== Out ==============================

[[1, 2, 3, 4, 5, 6],
 [2, 3, 6, 1, 4, 5],
 [3, 1, 5, 2, 6, 4],
 [4, 6, 2, 5, 1, 3],
 [5, 4, 1, 6, 3, 2],
 [6, 5, 4, 3, 2, 1]]

另外

通过使用这种解决方法,手头问题的答案变得更加容易。将矩阵视为这些子矩阵的组合,您可以知道这些组合中有多少可能是可能的。

作为结束语,稍微修改它以便允许它为任意( 但是甚至 )找到这个数组是一个很好的解决方案。 )n的数量。

答案 1 :(得分:0)

你有无限的递归。你的前三次迭代很好:你的第二行一次增加一种可能性,从200005变为214305.此时,你发现没有可能的选择。使用新的0,覆盖现有的0,然后无法回溯。其中每个都是错误:6是可能的值,并且您没有恢复代码。

这是我为追踪问题所做的改动;增加的是双星容器。当你有一个生病的程序,学习如何询问它在哪里受伤。打印功能是一种很好的工具。

def getPossibleMatrix(startMatrix, **iter=0**):
    if 0 not in flattenList(startMatrix):
        return startMatrix
    else:
        # find&fill in the first blank one
        ind=flattenList(startMatrix).index(0)
        y=ind//6
        x=ind%6
        possibles=getPossiblesForSquare(x,y,startMatrix)
        if len(possibles)==0:
            startMatrix[y][x]=0
            **print ("No possibles; current location remains 0")**
        else:
            startMatrix[y][x]=possibles[0]
            ****print ("Added first possible")
        print (startMatrix)
        if iter <= 6:**
            return getPossibleMatrix(startMatrix, **iter+1**) # <<BUG