C++子集和程序输出异常,疑全局函数中for/while循环失效
问题分析与修复方案
你的程序的核心漏洞不是ans或help函数的循环逻辑,而是在main函数中错误地修改了numOfNotes变量的值,导致传入ans函数的参数变成了0,完全破坏了后续的子集遍历逻辑。
具体错误点
看main函数中的这段代码:
cin>>numOfNotes>>money; int denomination[numOfNotes]; int i=0; while(numOfNotes){ cin>>denomination[i]; i++; numOfNotes--; // 这里把numOfNotes减到0了! } testCases--; ans(numOfNotes,money,denomination)==1?cout<<"Yes"<<endl:cout<<"No"<<endl;
当你读取完所有纸币面额后,numOfNotes已经被循环减到了0。此时调用ans(numOfNotes, money, denomination),传入的第一个参数是0,ans函数里的循环条件i < (1 << numOfNotes)就变成了i < 1,只会执行一次i=0的情况——而help(0, ...)返回的肯定是0(因为没有选中任何子集),所以程序输出No。
修复方法
你需要保留原始的纸币数量,不要修改numOfNotes变量,改用一个临时变量来控制循环:
cin>>numOfNotes>>money; int denomination[numOfNotes]; int i=0; int temp = numOfNotes; // 用临时变量代替原变量 while(temp){ cin>>denomination[i]; i++; temp--; } testCases--; ans(numOfNotes,money,denomination)==1?cout<<"Yes"<<endl:cout<<"No"<<endl;
其他值得优化的点
- 避免非标准变长数组:C++标准并不支持
int denomination[numOfNotes]这种变长数组(部分编译器如GCC支持作为扩展),建议改用std::vector<int>来存储面额,更安全且符合标准:vector<int> denomination(numOfNotes); for(int i=0; i<numOfNotes; i++){ cin>>denomination[i]; } help函数的逻辑可以简化:不需要单独写一个函数,直接在ans函数里计算当前掩码对应的子集和,减少函数调用开销:int ans(int numOfNotes,int money,int denomination[]){ for(int i=0;i<(1<<numOfNotes);i++){ int sum = 0; for(int j=0;j<numOfNotes;j++){ if(i & (1<<j)){ sum += denomination[j]; } } if(sum == money) return 1; } return 0; }- 变量命名更清晰:比如
help函数的i参数可以改成mask,更直观地表示它是子集的二进制掩码。
测试验证
修复后,输入测试用例1 3 3 1 1 1,程序会正确遍历所有8种子集组合,找到和为3的子集(三个1全选),输出Yes。
内容的提问来源于stack exchange,提问作者Akshat Singh




