Algorithm 如何通过行和列切换进行矩阵转换?
我得到了一个由元素1或1组成的方阵 或0。第i行切换切换所有第i行元素(1) 变为0,反之亦然),第j列切换切换所有 第j列元素。我得到了另一个平方矩阵 大小差不多。我想将初始矩阵更改为 使用最小切换次数的最终矩阵。比如说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] =
|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