使用生成函数方法的解决方案N(d, s)
可能最容易编程。您可以使用递归很好地对问题建模:
public int numPossibilities(int numDice, int sum) {
if (numDice == sum)
return 1;
else if (numDice == 0 || sum < numDice)
return 0;
else
return numPossibilities(numDice, sum - 1) +
numPossibilities(numDice - 1, sum - 1) -
numPossibilities(numDice - 1, sum - 7);
}
乍一看,这似乎是一个相当简单有效的解决方案。但是你会发现相同的值,很多计算numDice
和sum
可重复并重新计算一遍又一遍,使可能比你原来的强制方法效率较低这一解决方案。例如,在计算3
骰子的所有计数时,我的程序numPossibilities
总共运行了函数一次15106
,而不是只6^3 = 216
执行一次的循环。
为了使该解决方案可行,您需要添加另一种技术- 先前计算结果的记忆(缓存)。HashMap
例如,使用一个对象,您可以存储已经计算出的组合,并在运行递归之前先引用它们。当我实现一个缓存时,该numPossibilities
函数只运行151
总时间来计算3
骰子的结果。
随着骰子数量的增加,效率提高也越来越大(结果基于我自己实现的解决方案的仿真结果):
# Dice | Brute Force Loop Count | Generating-Function Exec Count
3 | 216 (6^3) | 151
4 | 1296 (6^4) | 261
5 | 7776 (6^5) | 401
6 | 46656 (6^6) | 571
7 | 279936 (6^7) | 771
...
20 | 3656158440062976 | 6101