我面临一个问题,对于给定数量的合同,我们需要针对所有可能的独特定价方案进行投标。例如,说有2个合同A和B。我们必须对三种情况下仅获胜A,仅获B或A&B的价格进行定价。
如果有三个合同A,B和C,根据我的计算,这将导致7种可能的定价方案组合; A,B,C,AB,AC,BC,ABC。
我使用Javascript计算了公式,如下所示:
function contractCount(numContracts) {
return (2 ** numContracts) - 1;
}
我是通过反复试验并在电子表格中进行操作来做到这一点的。这似乎是一个递归问题,但是我不知道如何递归地实现该解决方案?另外,我希望有人可以用简单的方式解释为什么我的上述解决方案有效。我可以理解,答案始终是合同数量加上(合同数量-1)中可能出现的情况,上述解决方案似乎与我对问题的头脑理解完全没有关系。
答案 0 :(得分:1)
这只是出于一些考虑
仅
'A'
产生A
使用
'A', 'B'
,您将获得A AB B is the value of the next call and this is added to A B and used as single result
使用
'A', 'B', 'C'
,您将获得A AB ABC AC B BC C
function f(v, ...a) {
var temp = a.length ? f(...a) : [];
return a.length
? [[v], ...temp.map(a => [v, ...a]), ...temp]
: [[v]];
}
console.log(f('A').map(a => a.join('')));
console.log(f('A', 'B').map(a => a.join('')));
console.log(f('A', 'B', 'C').map(a => a.join('')));
console.log(f('A', 'B', 'C', 'D').map(a => a.join('')));
.as-console-wrapper { max-height: 100% !important; top: 0; }
答案 1 :(得分:0)
假设1 =获胜而0-未获胜
考虑A和B合约
那么所有可能的组合都是
A | B
0 | 0
0 | 1
1 | 0
1 | 1
但是您要消除0-0组合,因为至少应该有一个获胜。因此,不可能的组合是3 = 2 ^ 2-1-
对于3个合约A,B,C
A | B | C
0 | 0 | 0
0 | 0 | 1
0 | 1 | 0
0 | 1 | 1
1 | 0 | 0
1 | 0 | 1
1 | 1 | 0
1 | 1 | 1
再次,我们必须消除0-0-0组合。因此,不可能的组合是7 = 2 ^ 3-1
同样,在您的用例中,可能的组合数= 2 ^ n-1
答案 2 :(得分:0)
简而言之, 2 ** 3表示2x2x2等于8,并且在组合中必须有两个操作数,因此开始操作该操作数时不能与他自己组合,因此我们必须减去一个数字,这就是为什么要使用的原因。
(2 ** 3)-1
答案 3 :(得分:0)
我不确定您是要查找数量还是实际组合。计数只是一个数学问题,但是返回组合需要更多的工作。递归查找组合是backtracking algorithms
的经典应用程序
function groupByCount(arr, result = []) {
const backtrack = (n, k = 0, a = []) => {
if (k == n) return result.push(a.map((c, i) => c ? arr[i] : undefined).filter(i => i != undefined))
k++
for (let i = 0; i < 2; i++) {
a[k - 1] = i
backtrack(n, k, a)
}
}
backtrack(arr.length)
return result
}
let comb = groupByCount(['A', 'B', 'C'])
console.log(comb.join(' | '))
console.log(groupByCount(['A', 'B']).join(' | '))
这将构建一个布尔区域,表示每个索引是否在解决方案中。每次阵列填满时,都会推送解决方案。在它点击之前,我需要花些时间盯着它-至少对我来说是如此。注意:从技术上讲,空集是解决方案的一部分,因此它也将返回它。
如果您只是在考虑组合的数量,这是一种考虑的好方法。您可以考虑一下,如果您的每个合同都是二进制数字。因此,在您的A,B,C示例中,只有A可能表示为001
,只有B 010
和C 100
。当您组合它们时,您只需组合位,以便AB为011
,AC,101
,ABC 111
。等等,您会注意到,所有组合均以二进制数字表示,位数与您拥有的项数相同,并且每种组合的计数范围为001
至111
。换句话说,组合的数量将始终与二进制数字相同,其中的许多数字用1
填充。
使用3:111
= 7
4:1111
= 15
您可以使用parseInt('1'.repeat(n), 2)
在JavaScript中进行检查,其中n
是合同编号。
for (let n = 1; n < 8; n++){
let b = '1'.repeat(n)
console.log(n + ': ' + b + ' = ' + parseInt(b, 2) + ' = ' + (2**n -1))
}
当然,这并不是一种非常有效的方法,因为它只是表示组合数是n -1的幂2的另一种方式。
答案 4 :(得分:0)
发电机非常适合这种计算
const None =
Symbol ()
const combinations = (...xs) =>
{ const loop = function* (comb, [x = None, ...xs])
{ if (x === None)
return yield comb
yield* loop ([...comb, x], xs)
yield* loop (comb, xs)
}
return Array.from (loop ([], xs))
}
console.log (combinations ('a'))
// [ [a], [] ]
console.log (combinations ('a', 'b'))
// [ [a,b], [a], [b], [] ]
console.log (combinations ('a', 'b', 'c'))
// [ [a,b,c], [a,b], [a,c], [a], [b,c], [b], [c], [] ]