1、素数环:从1到20这20个数摆成一个环,要求相邻的两个数的和是一个素数。

let ans = [], flagArr = []
function primeSum(a, b) {
    let sum = a+b, k = 2
    for (; k <= Math.sqrt(sum); k++) {
        if (!(sum % k)) return false
    }
    return true
}
function primeRing(num, k=1) {
    for (let i = 1; i < num+1; i++) {
        if (!flagArr[i-1] && primeSum(ans[k-1], i)) {
            flagArr[i-1] = 1
            ans[k] = i
            if (k == num-1) {
                if (primeSum(ans[num-1], ans[0])) console.log(ans)
            } else {
                primeRing(num, k+1)
            }
            flagArr[i-1] = 0
        }
    }
}
for (let i=1; i <= 20; i++) {
    ans[0] = i
    flagArr[i-1] = 1
    primeRing(20)
    flagArr[i-1] = 0
}

这样得到的结果数量除以20才是符合要求的环的数量,暂时不作去重

2、设有n个整数的集合{1,2,...,n},从中任意取出r个数进行排列(r<n),试列出所有的排列。

let ans = [], flagArr = []
function allRank(n, k=1) {
    for (let i = 1; i < n+1; i++) {
        if (!flagArr[i-1]) {
            flagArr[i-1] = 1
            ans.push(i)
            if (k === n) console.log(ans)
            else allRank(n, k+1)
            flagArr[i-1] = 0
            ans.pop()
        }
    }
}
//test
allRank(5)

3、任何一个大于1的自然数n,总可以拆分成若干个小于n的自然数之和。求所有拆分方法。

let target = 5, ans = [1] // 记住这个1
function splitANum(num) {
    // i取值为当前数组的最后一项,保证结果数组的每一项递增,从而使最后得到的所有拆分方法不重复;i小于等于num以保证num-i不小于0
    for (let i = ans[ans.length-1]; i <= num; i++) {
        if (i == target) return // 拆分项不允许等于拆分目标
        ans.push(i)
        num -= i
        if (num == 0) { //拆分完毕,打印结果
            console.log(ans.slice(1)) //去掉最开始的1
        }
        else splitANum(num) //继续拆分
        // 游戏回档
        ans.pop()
        num += i
    }
}
//test
splitANum(target)