Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/11.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Algorithm 如何通过行和列切换进行矩阵转换?_Algorithm - Fatal编程技术网

Algorithm 如何通过行和列切换进行矩阵转换?

Algorithm 如何通过行和列切换进行矩阵转换?,algorithm,Algorithm,我得到了一个由元素1或1组成的方阵 或0。第i行切换切换所有第i行元素(1) 变为0,反之亦然),第j列切换切换所有 第j列元素。我得到了另一个平方矩阵 大小差不多。我想将初始矩阵更改为 使用最小切换次数的最终矩阵。比如说 |0 0 1| |1 1 1| |1 0 1| 到 需要切换第一行和最后一行 专栏 正确的算法是什么?如果您只能切换行,而不能切换列,那么只有一部分矩阵可以转换为最终结果。如果是这样的话,那就很简单了: for every row, i: if matrix1[i] =

我得到了一个由元素1或1组成的方阵 或0。第i行切换切换所有第i行元素(1) 变为0,反之亦然),第j列切换切换所有 第j列元素。我得到了另一个平方矩阵 大小差不多。我想将初始矩阵更改为 使用最小切换次数的最终矩阵。比如说

|0 0 1|
|1 1 1|
|1 0 1|

需要切换第一行和最后一行 专栏


正确的算法是什么?

如果您只能切换行,而不能切换列,那么只有一部分矩阵可以转换为最终结果。如果是这样的话,那就很简单了:

for every row, i:
  if matrix1[i] == matrix2[i]
    continue;
  else
    toggle matrix1[i];
    if matrix1[i] == matrix2[i]
      continue
    else
      die("cannot make similar");

这并不总是可能的。如果你从一个偶数为1的2x2矩阵开始,你永远不会得到一个奇数为1的最终矩阵。

我想出了一个蛮力算法。

该算法基于两个猜想:
(因此,它可能不适用于所有矩阵-稍后我将验证它们)

  • 最小(切换次数)解决方案将只包含一次特定的行或列
  • 无论我们以什么顺序应用这些步骤来转换矩阵,我们都会得到相同的结果
算法:
假设矩阵m=[[1,0],[0,1]]

m: 1 0
   0 1
我们生成所有行和列编号的列表,
像这样:
['r0','r1','c0','c1']

现在我们使用蛮力,也就是检查每一个可能的步骤组合。
例如,
我们从一步解决方案开始,
ksubsets=['r0']、['r1']、['c0']、['c1']


如果没有元素是解决方案,则继续进行两步解决方案,
ksubsets=['r0','r1'],['r0','c0'],['r0','c1'],['r1','c0'],['r1','c1'],['c0','c1']

等等

ksubsets元素(combo)是要在矩阵中应用的切换步骤列表


Python实现(在版本2.5上测试)



这是一个状态空间搜索问题。您正在搜索从起始状态到目标状态的最佳路径。在这种特殊情况下,“最佳”定义为“最小操作次数”

状态空间是通过行和列切换操作从起始位置生成的二进制矩阵集

假设目的地在状态空间中(在某些情况下,这不是一个有效的假设:参见Henrik的答案),我会尝试使用一个经典的启发式搜索(可能是a*,因为它是同类中最好的)算法来解决问题,看看发生了什么

第一个最明显的启发是“正确元素的数量”

任何一本像样的人工智能教科书都会讨论搜索和A*算法

您可以将矩阵表示为非负整数,在支持64位长无符号整数的系统上,矩阵中的每个单元格正好对应于整数中的一位,这使您可以处理高达8x8的任何内容。然后可以对数字使用异或操作来实现行和列切换操作


警告:原始总状态空间大小为2^(N^2),其中N是行(或列)数。对于4x4矩阵,这是2^16=65536个可能的状态。

一般来说,问题没有解决方案。要了解这一点,请注意,将矩阵A转换为矩阵B相当于将矩阵A-B(使用二进制算术计算,以便0-1=1)转换为零矩阵。查看矩阵A-B,并应用列切换(如有必要),以便第一行全部变为0或1。此时,您已经完成了列切换——如果切换一个列,则必须切换所有列以获得正确的第一行。如果此时即使有一行是0和1的混合,问题也无法解决。如果现在每一行都是0或1,则通过切换适当的行以达到零矩阵,问题可以解决


要获得最小值,请比较第一行变为0和1时所需的切换次数。在OP的示例中,候选项将切换第3列和第1行,或者切换第1列和第2列以及第2行和第3行。事实上,您可以通过查看第一个解决方案并查看切换次数是否小于或大于N来简化此过程——如果大于N,则切换相反的行和列。

算法

将问题从“尝试将A转换为B”简化为“尝试将M转换为0”,其中M=A xor B。现在所有必须切换的位置都有一个1

考虑M中的任意位置。它仅受一个列切换和一个行切换的影响。如果它的初始值是V,列切换的存在是C,行切换的存在是R,那么最终的值F是V xor C xor R。这是一个非常简单的关系,它使得问题很容易解决

注意,对于每个位置,R=F xor V xor C=0 xor V xor C=V xor C。如果我们设置C,那么我们强制R的值,反之亦然。这太棒了,因为这意味着如果我设置任何行切换的值,那么我将强制所有列切换。任何一个列切换都将强制所有行切换。如果结果是0矩阵,那么我们有一个解。我们只需要试两个案例

伪代码

function solve(Matrix M) as bool possible, bool[] rowToggles, bool[] colToggles:
    For var b in {true, false}
        colToggles = array from c in M.colRange select b xor Matrix(0, c)
        rowToggles = array from r in M.rowRange select colToggles[0] xor M(r, 0)
        if none from c in M.colRange, r in M.rowRange
                where colToggle[c] xor rowToggle[r] xor M(r, c) != 0 then
            return true, rowToggles, colToggles
        end if
    next var
    return false, null, null
end function
分析

分析是微不足道的。我们尝试两种情况,在这两种情况下,我们先运行一行,然后运行一列,然后运行所有单元格。因此,如果有r行和c列,这意味着矩阵的大小为n=c*r,那么时间复杂度为O(2*(c+r+c*r))=O(c*r)=O(n)。我们使用的唯一空间是存储输出所需的空间=O(c+r)

因此,该算法在矩阵大小上采用时间线性,在输出大小上采用空间线性。由于明显的原因,它是渐近最优的。

而不是
# Recursive definition (+ is the join of sets)
# S = {a1, a2, a3, ..., aN}
#
# ksubsets(S, k) = {
# {{a1}+ksubsets({a2,...,aN}, k-1)}  +
# {{a2}+ksubsets({a3,...,aN}, k-1)}  +
# {{a3}+ksubsets({a4,...,aN}, k-1)}  +
# ... }
# example: ksubsets([1,2,3], 2) = [[1, 2], [1, 3], [2, 3]]
def ksubsets(s, k):
    if k == 1: return [[e] for e in s]
    ksubs = []
    ss = s[:]
    for e in s:
        if len(ss) < k: break
        ss.remove(e)
        for x in ksubsets(ss,k-1):
            l = [e]
            l.extend(x)
            ksubs.append(l)
    return ksubs

def toggle_row(m, r):
    for i in range(len(m[r])):
        m[r][i] = m[r][i] ^ 1

def toggle_col(m, i):
    for row in m:
        row[i] = row[i] ^ 1

def toggle_matrix(m, combos):
    # example of combos, ['r0', 'r1', 'c3', 'c4']
    # 'r0' toggle row 0, 'c3' toggle column 3, etc.
    import copy
    k = copy.deepcopy(m)
    for combo in combos:
        if combo[0] == 'r':
            toggle_row(k, int(combo[1:]))
        else:
            toggle_col(k, int(combo[1:]))

    return k

def conversion_steps(sM, tM):
# Brute force algorithm.
# Returns the minimum list of steps to convert sM into tM.

    rows = len(sM)
    cols = len(sM[0])
    combos = ['r'+str(i) for i in range(rows)] + \
             ['c'+str(i) for i in range(cols)]

    for n in range(0, rows + cols -1):
        for combo in ksubsets(combos, n +1):
            if toggle_matrix(sM, combo) == tM:
                return combo
    return []
m: 0 0 0
   0 0 0
   0 0 0

k: 1 1 0
   1 1 0
   0 0 1
>>> m = [[0,0,0],[0,0,0],[0,0,0]]
>>> k = [[1,1,0],[1,1,0],[0,0,1]]
>>> conversion_steps(m, k)
['r0', 'r1', 'c2']
>>> 
function solve(Matrix M) as bool possible, bool[] rowToggles, bool[] colToggles:
    For var b in {true, false}
        colToggles = array from c in M.colRange select b xor Matrix(0, c)
        rowToggles = array from r in M.rowRange select colToggles[0] xor M(r, 0)
        if none from c in M.colRange, r in M.rowRange
                where colToggle[c] xor rowToggle[r] xor M(r, c) != 0 then
            return true, rowToggles, colToggles
        end if
    next var
    return false, null, null
end function