C#实现彩票中奖概率计算时特定输入无运行结果问题排查
代码问题定位与解决方案
核心异常原因
输入45、15、III时程序无输出并非语法报错,是运行时计算完全卡滞导致,具体由三个叠加问题引发:
- 递归组合数的时间复杂度爆炸
原代码用帕斯卡递归公式实现组合数计算,递归的总调用次数和组合数本身的数值完全相等——比如计算C(45,15)时,会触发超过300亿次递归调用,CPU被完全占满,程序根本无法在可接受时间内执行到输出语句,从控制台视角看就像没有任何输出。
对比能正常运行的测试场景:输入49、6、I时,最大组合数为C(49,6),仅约1400万次调用,几秒就能跑完出结果,所以表现正常。 - 递归边界校验缺失
原bc方法仅在k==0或k==n时返回终止值,没有处理k <0或k>n的非法组合场景,遇到此类参数会无限递归直到栈溢出崩溃。 - 奖级匹配参数与题目要求不符
题目明确奖级规则为:I匹配6个号码、II匹配5个号码、III匹配4个号码,但原代码写死的匹配数为I=6、II=4、III=2,就算程序能跑完,输出的概率值也完全错误。
修复方案
1. 修正奖级计算的匹配参数
把switch分支内的匹配数调整为题目要求的值:
- 奖级I:保持匹配数6不变
- 奖级II:把原来的匹配数4改为5,对应计算式为
bc(k,5) * bc(n -k, k -5) / bc(n,k) - 奖级III:把原来的匹配数2改为4,对应计算式为
bc(k,4) * bc(n -k, k -4) / bc(n,k)
2. 重构组合数计算方法
替换原递归实现为O(k)时间复杂度的迭代实现,利用组合数对称性减少计算量,同时加上边界校验,从根本上避免卡滞:
private static double bc(int n, int k) { // 非法参数直接返回0 if (k < 0 || k > n) return 0; // 利用组合数对称性减少循环次数:C(n,k) = C(n, n-k) if (k > n - k) k = n - k; double result = 1; for (int i = 1; i <= k; i++) { // 逐步连乘计算,无递归、无重复调用 result *= (n - k + i) / (double)i; } return result; }
这种实现哪怕计算C(45,15)也仅需要15次循环,毫秒级就能出结果,完全不会卡滞。
3. 可选优化
去掉switch分支内不必要的return语句,让程序跑完输出后能正常暂停控制台窗口,避免程序瞬间退出看不到结果。
优化后测试输入45、15、III的场景,程序会立刻计算出对应4个匹配的中奖概率,按10位小数格式输出。
内容的提问来源于stack exchange,提问作者Bodor Arianna
相关产品推荐
相关产品推荐

