鉴于数字1,2,3,4,5,6,7,8,我需要它们来替换x,以便每一边加上中心的数字。
*-*---*-*
|x| x |x|
*-*---*-*
|x| 12|x|
*-*---*-*
|x| x |x|
*-*---*-*
作为一个开始,我已经圈出数字以找到所有可能的组合。
var range = [1,2,3,4,5,6,7,8];
var target = 12;
var matches = [];
for (x = 0; x < range.length; x ++){
for (y = 0; y < range.length; y ++){
if (y === x){
continue;
}
for (z = 0; z < range.length; z ++){
if (z === y || z === x){
continue;
}
if (range[x] + range[y] + range[z] === target){
matches.push([range[x], range[y], range[z]]);
}
}
}
}
接下来,我将这些数字端到端地加在一起
for (j=0; j < matches.length; j++){
for (k=0; k < matches.length; k++){
if (j==k) continue;
//if (matches[j][2] != matches[k][0]) continue;
for (l=0; l < matches.length; l++){
if (l==j || l==k) continue;
//if (matches[k][2] != matches[l][0]) continue;
for (m=0; m < matches.length; m++){
if (m==j || m==k || m==l) continue;
if (matches[l][2] != matches[m][0]) continue;
if (matches[m][2] != matches[j][0]){
console.log(matches[j], matches[k], matches[l], matches[m]);
}
}
}
}
}
我目前没有办理登机手续,以确保每个号码组合只使用一次,这就是我解决这个问题的方法。
我真的想知道解决这个问题的整体更好的方法。
答案 0 :(得分:1)
实际上不需要枚举所有40,320个数字的排列,因为8个位置中的4个通过从目标中减去两个相邻值来自动填充。因此,只有4个变量,最多1,680个排列:
A B C
D 12 E
F G H
A和B的任何选择都决定了C,那么任何D的选择都决定了F,任何E的选择决定了H和G,所以A,B D和E都是变量。
您可以使用4个嵌套循环迭代执行此操作,如下所示,或递归地执行此操作,这将更容易适应其他网格大小。
for A is 1 to 8
for B is any available number < target - A
C = target - (A + B)
if C is not available, skip to next B
for D is any available number < target - A
F = target - (A + D)
if F is not available, skip to next D
for E is any available number < target - C
H = target - (C + E)
if H is not available, skip to next E
G = target - (F + H)
if G is available, store this combination
}
}
}
}
在最简单的迭代形式中,使用Daniel Wagner的建议只生成可以旋转和镜像的唯一解决方案,您将获得类似下面的代码示例。内循环中的代码只运行了56次,总共有142 indexOf()
次调用。
function numberSquare(target) {
for (var a = 1; a < 9; a++) {
for (var c = a + 1; c < 9 && c < target - a; c++) {
var b = target - (a + c);
if ([a,c].indexOf(b) > -1 || b > 8) continue;
for (var f = c + 1; f < 9 && f < target - a; f++) {
var d = target - (a + f);
if ([a,b,c,f].indexOf(d) > -1 || d > 8) continue;
for (var h = a + 1; h < 9 && h < target - c && h < target - f; h++) {
if ([b,c,d,f].indexOf(h) > -1) continue;
var e = target - (c + h);
if ([a,b,c,d,f,h].indexOf(e) > -1 || e > 8) continue;
var g = target - (f + h);
if ([a,b,c,d,e,f,h].indexOf(g) > -1 || g > 8) continue;
document.write([a,b,c] + "<br>" + [d,'_',e] + "<br>" + [f,g,h] + "<br><br>");
}
}
}
}
}
numberSquare(12);
document.write("× 4 rotations and 2 mirrorings (8 solutions per result)");
答案 1 :(得分:1)
我花了一点时间重新思考这个方法。我认为一个很好的解决方案是拥有一个索引对象,以便循环组成中心数字的不同组合,你知道下一个数字需要从当前选择的最后一个数字开始,所以如果你采取
[1, 3, 8]
您知道您需要查看以8开头的组合
{
...,
8: [[8, 1, 3], [8, 3, 1]]
}
这将只留下两个选项。
我确信我的代码可以重构,但已经很晚了!
var range = [1,2,3,4,5,6,7,8];
var target = 13;
var matches = [];
var keyedMatches = {
"1": [],
"2": [],
"3": [],
"4": [],
"5": [],
"6": [],
"7": [],
"8": []
};
let firstSteps = 0;
for (x = 0; x < range.length; x ++){firstSteps++
for (y = 0; y < range.length; y ++){
if (y === x){
continue;
}firstSteps++
for (z = 0; z < range.length; z ++){
if (z === y || z === x){
continue;
}firstSteps++
if (range[x] + range[y] + range[z] === target){
matches.push([range[x], range[y], range[z]]);
keyedMatches[range[x]].push([range[x], range[y], range[z]])
}
}
}
}
console.log(keyedMatches);
let secondSteps = 0;
var currentSelection = [];
var usedNums = [];
for (j = 0; j < matches.length; j ++){secondSteps++;
usedNums.push(matches[j][0]);
usedNums.push(matches[j][1]);
usedNums.push(matches[j][2]);
var step2 = keyedMatches[usedNums[usedNums.length-1]];
for (k=0; k < step2.length; k++){
if(checkUsed(usedNums, step2[k])) continue;
usedNums.push(step2[k][1]);
usedNums.push(step2[k][2]);
var step3 = keyedMatches[usedNums[usedNums.length-1]];
for (l=0; l < step3.length; l++){
if(checkUsed(usedNums, step3[l])) continue;
usedNums.push(step3[l][1]);
usedNums.push(step3[l][2]);
var step4 = keyedMatches[usedNums[usedNums.length-1]];
for (m=0; m < step4.length; m++){
if(usedNums.indexOf(step4[m][1]) !== -1) continue;
if (step4[m][2] != usedNums[0]) continue;
usedNums.push(step4[m][1]);
console.log(usedNums);
// remove the used numbers
usedNums.pop();
}
// remove the used numbers
usedNums.pop();
usedNums.pop();
}
// remove the used numbers
usedNums.pop();
usedNums.pop();
}
usedNums = [];
}
function checkUsed(unum, nnum){
if (unum.indexOf(nnum[1]) === -1 && unum.indexOf(nnum[2]) === -1){
return false;
}
return true;
}
答案 2 :(得分:0)
这是一个简单的实现。我确信通过动态编程方法我可以提供更有效的解决方案,但是到目前为止由于我的时间有限,我只能提出一种直接的方法。由于我使用one of the most efficient permutation algorithms in JS,因此结果非常快。
它的结果如下;
返回的有效排列应解释为从左上角开始并顺时针插入的值。
function solve4(n,a){
function perm(a){
var r = [[a[0]]],
t = [],
s = [];
if (a.length <= 1) return a;
for (var i = 1, la = a.length; i < la; i++){
for (var j = 0, lr = r.length; j < lr; j++){
r[j].push(a[i]);
t.push(r[j]);
for(var k = 1, lrj = r[j].length; k < lrj; k++){
for (var l = 0; l < lrj; l++) s[l] = r[j][(k+l)%lrj];
t[t.length] = s;
s = [];
}
}
r = t;
t = [];
}
return r;
}
function validChoices(chs,n){//console.log(chs)
return chs.filter(ch => ch[0]+ch[1]+ch[2] === n &&
ch[2]+ch[3]+ch[4] === n &&
ch[4]+ch[5]+ch[6] === n &&
ch[6]+ch[7]+ch[0] === n);
}
return validChoices(perm(a),n);
}
console.log(solve4(12,[1,2,3,4,5,6,7,8]));
因此,您会看到输入12
和[1,2,3,4,5,6,7,8]
,我们有8个单独的解决方案;
[ [ 1, 5, 6, 4, 2, 7, 3, 8 ],
[ 6, 4, 2, 7, 3, 8, 1, 5 ],
[ 2, 7, 3, 8, 1, 5, 6, 4 ],
[ 3, 8, 1, 5, 6, 4, 2, 7 ],
[ 3, 7, 2, 4, 6, 5, 1, 8 ],
[ 2, 4, 6, 5, 1, 8, 3, 7 ],
[ 6, 5, 1, 8, 3, 7, 2, 4 ],
[ 1, 8, 3, 7, 2, 4, 6, 5 ] ]