由于排列会产生暴力,因此在开发与此类似的算法时,它们应该是最后的手段。大多数时候不需要它们。
正如我上面评论的那样,我有一种感觉,一个策略可以是首先对r
and c
数组降序排列,从较大的数组开始。我还没有时间实现 JS 代码来解决这个问题,所以我没有机会进行彻底的测试。请看一下,如果发现缺陷请指出。
在下面我们尝试的算法的视觉表示中r = [1,3,1,3]
and c = [3,2,1,2]
. X
表示已占用的单元格,红点表示不可触及的单元格,而空的显然是空闲单元格。因此,在表示单元格的实际算法中,我们需要像这样的数据类型{value: false, avail: false}
一个红点{value: false, avail: true}
意味着一个自由空间。或者为了节省空间和速度,您可以使用类似的数据类型0b00
对于红点,0b01
以获得可用空间和0b1X
对于被占用的(X在这里表示不关心)单元格。
Note:值得一提的是我们处理的第 3 步c[0]
。我们插入三个之后X
我们必须检查被占用的行X
s 更新这些行中空单元格的状态。在这种情况下,对于 r[2],所有空单元格都变得不可触及。
Edit:
好吧..好吧,因为我们不需要在类似二维数组的结构中构建解决方案,而只需要回答所提供的数据是否有意义,所以我提出了另一个更简单的想法,它基本上基于上述方法。我真的不认为它能比这更快。它在大约 50 毫秒内解决了 999 x 1000 板的问题。
让我们开始吧。
- 输入是
r = [2, 3, 2]; c = [1, 1, 3, 2];
然而这里有一个重要的条件是both c
and r
数组的总和应该相同。我们可以简单地在代码开头检查这一点,或者保留它,执行以下步骤,如果它们通过,则仅在以下情况下进行检查:c
满是 0。以下代码更喜欢后一种方法。
- Sort
r
如此下降;r = [3, 2, 2]; c = [1, 1, 3, 2];
- 尝试减少
r[0]
(第一种情况为 3)许多非零元素c
1.现在c
变成[0, 0, 2, 2]
。如果失败则不再尝试并返回false
.
- 现在我们已经完成了行
r[0]
,递归调用函数r = [2, 2]; c = [0, 0, 2, 2];
while r.length
大于 0 且 bool 参数b
is true
。下一次通话将是r = [2]; c = [0, 0, 1, 1];
最后r = []; c = [0, 0, 0, 0];
- 如果最终递归调用为空
r
被调用然后检查b
is true
以及所有项目c
are 0
. (b && cs.every(n => !n)
).
我相信这很好,但由于我没有你的测试用例,所以你可以尝试一下。我相信它会通过时间考验。这是最简单的代码。我在这里测试rs = [7,3,5,4,6,2,8]
and cs = [7,1,6,3,4,5,2,7]
。看起来像;
71634527
7 x xxxxxx
3 x x x
5 x x xx x
4 x x x x
6 x xxxx x
2 x x
8 xxxxxxxx
function nonogram(rs,cs){
function runner(rs,cs, b = true){//console.log(rs,cs,b)
return b && rs.length ? runner(rs.slice(1), // rows argument
cs.map(e => rs[0] ? e ? (b = !--rs[0], e-1) // cols argument
: e
: e),
b) // bool argument
: b && cs.every(n => !n);
}
return runner(rs.sort((a,b) => b-a), cs);
}
var rs = [7,3,5,4,6,2,8],
cs = [7,1,6,3,4,5,2,7],
result;
console.time("test");
result = nonogram(rs,cs);
console.timeEnd("test");
console.log(result);