我正在寻找一些指示,因为我不知道从哪里开始研究这个。
我在每个单元格中都有一个0或1的2D矩阵,例如:
1 2 3 4
A 0 1 1 0
B 1 1 1 0
C 0 1 0 0
D 1 1 0 0
我想对它进行排序,使其尽可能为“上三角”,如下:
4 3 1 2
B 0 1 1 1
A 0 1 0 1
D 0 0 1 1
C 0 0 0 1
行和列必须保持完整,即元素不能单独移动,只能“整体”交换。
据我所知,可能存在一种病态情况,其中矩阵具有多个可能的排序结果(即相同的形状,但“原始”行/列的标识不同。)
那么,任何人都可以建议我在哪里找到一些起点吗?现有的库/算法会很棒,但我会知道我想要解决的问题的名称!
我怀疑这是一个线性代数问题,也许有一种适用的图像处理技术。
除了其他任何想法,我最初的猜测只是在行上写一个简单的插入排序,然后对列进行迭代,直到它稳定(并希望检测病理情况不太难。)
更多细节:有关我正在尝试做的更多信息可能有助于澄清。每行代表一个竞争者,每列代表一个挑战。每个1或0代表竞争对手在特定挑战中的“成功”。
通过对矩阵进行排序以使所有1都位于右上方,我希望随后提供每个挑战的内在难度和竞争对手排名的排名(这将考虑他们成功的挑战的难度) at,而不仅仅是成功的数量。)
关于已接受答案的说明:我已接受模拟退火作为“答案”,但需要注意的是此问题没有正确答案。这似乎是一个很好的方法,虽然我实际上没有设法得到一个适用于我的问题的评分函数。
答案 0 :(得分:6)
基于simulated annealing的算法可以在没有太多麻烦的情况下处理这类事情。如果你的小矩阵很可能是一个固定的解决方案,那就太好了,但如果你的矩阵变得更大并且问题变得更加困难,那就太棒了。
(但是,你也不希望插入可以逐步完成。)
<强>预赛强>
设计一个“得分”矩阵的表现函数 - 更接近三角形的矩阵应得到比三角形y更小的矩阵。
在矩阵上设计一组允许的操作。您的描述有点模棱两可,但如果您可以交换行,那么一个操作将是SwapRows(a, b)
。另一个可能是SwapCols(a, b)
。
退火循环
我不会在这里给出完整的论述,但这个想法很简单。您可以使用操作对矩阵执行随机转换。您可以测量操作后矩阵的“更好”程度(使用操作前后的性能函数)。然后你决定是否提交转换。你重复这个过程很多。
决定是否提交转换是有趣的部分:您需要决定是否执行该操作。在退火过程结束时,您只接受改善矩阵分数的转换。但是在早些时候,在一个更混乱的时代,你允许转换不会提高分数。在一开始,算法是“热”的,任何事情都会发生。最终,算法冷却,只允许良好的转换。如果线性冷却算法,则选择是否接受转换是:
public bool ShouldAccept(double cost, double temperature, Random random) {
return Math.Exp(-cost / temperature) > random.NextDouble();
}
您应该阅读Numerical Recipes中包含的优秀信息,以获取有关此算法的更多信息。
长话短说,你应该学习一些这些通用算法。这样做可以解决难以分析解决的大类问题。
评分算法
这可能是最棘手的部分。你需要设计一个能够指导退火过程实现目标的记分员。记分员应该是一个连续的函数,当矩阵接近理想的解时,它会产生更大的数字。
您如何衡量“理想解决方案” - 三角形?这是一个天真而简单的得分手:对于每一点,你都知道它应该是1
还是0
。如果矩阵是正确的,则为分数添加+1,如果是错误则为-1。这里有一些代码,所以我可以明确(未经过测试!请查看!)
int Score(Matrix m) {
var score = 0;
for (var r = 0; r < m.NumRows; r++) {
for (var c = 0; c < m.NumCols; c++) {
var val = m.At(r, c);
var shouldBe = (c >= r) ? 1 : 0;
if (val == shouldBe) {
score++;
}
else {
score--;
}
}
}
return score;
}
使用这种评分算法,1和0的随机字段将得分为0.“相反”三角形将给出最大的负分数,正确的解决方案将给出最大的正分数。两个分数的差异会给你带来成本。
如果这个得分手不适合你,那么你需要“调整”它直到它产生你想要的矩阵。
此算法基于这样一个前提,即调整此记分器比设计用于对矩阵进行排序的最佳算法要简单得多。
答案 1 :(得分:1)
我提出了以下算法,它似乎正常工作。
阶段1:移动大多数1
s的行和大多数1
s的行。
1
s来对行进行排序。我们不在乎
如果2行具有相同数量的1
s。1
。我们不在乎
如果2个cols的数量相同
1
秒。 阶段2:重复阶段1 ,但要有额外的标准,以便我们满足三角矩阵变形。
行标准:如果2行具有相同数量的1
s,我们将向上移动以较少0
秒开头的行。
cols的标准:如果2个col具有相同数量的1
s,我们将向右移动在底部具有较少0
s的col。
示例:
第1阶段
1 2 3 4 1 2 3 4 4 1 3 2
A 0 1 1 0 B 1 1 1 0 B 0 1 1 1
B 1 1 1 0 - sort rows-> A 0 1 1 0 - sort cols-> A 0 0 1 1
C 0 1 0 0 D 1 1 0 0 D 0 1 0 1
D 1 1 0 0 C 0 1 0 0 C 0 0 0 1
第2阶段
4 1 3 2 4 1 3 2
B 0 1 1 1 B 0 1 1 1
A 0 0 1 1 - sort rows-> D 0 1 0 1 - sort cols-> "completed"
D 0 1 0 1 A 0 0 1 1
C 0 0 0 1 C 0 0 0 1
编辑:事实证明我的算法始终没有给出正确的三角矩阵 例如:
第1阶段
1 2 3 4 1 2 3 4
A 1 0 0 0 B 0 1 1 1
B 0 1 1 1 - sort rows-> C 0 0 1 1 - sort cols-> "completed"
C 0 0 1 1 A 1 0 0 0
D 0 0 0 1 D 0 0 0 1
第2阶段
1 2 3 4 1 2 3 4 2 1 3 4
B 0 1 1 1 B 0 1 1 1 B 1 0 1 1
C 0 0 1 1 - sort rows-> C 0 0 1 1 - sort cols-> C 0 0 1 1
A 1 0 0 0 A 1 0 0 0 A 0 1 0 0
D 0 0 0 1 D 0 0 0 1 D 0 0 0 1
(no change)
(*)或许阶段3 会增加良好的结果。在该阶段,我们将以较少0
s开头的行放在顶部。
答案 2 :(得分:1)
寻找Anna Lubiw关于“矩阵的双重词汇排序”的1987年论文。
下面有一个引文。订单与您要查找的内容不同,但非常接近。如果不出意外,你应该可以从中获得一个好主意。
答案 3 :(得分:0)
这是一个起点:
将每行从二进制位转换为数字
按降序对数字进行排序。
然后将每一行转换回二进制。
答案 4 :(得分:0)
基本算法:
希望你应该有一个尽可能靠近右上角三角形区域的矩阵。
答案 5 :(得分:0)
将行视为二进制数,最左边的列为最高位,并按降序排列,从上到下
将列视为二进制数,最下面的行为最高位,并按从左到右的升序排序。
重复直到达到固定点。该算法终止的证据留给读者作为练习。