CS50x Pset3 Tideman:vote与preferences函数check50报错求助
问题描述
我在完成CS50x的Pset3 Tideman题目时,编写了vote和record_preferences函数的代码,但运行check50时出现以下问题:
- vote函数未正确设置ranks数组
- 首个投票者的preferences未被正确设置
不过后续测试显示,record_preferences能为其他投票者正确设置preferences,依赖该数组的其他功能也可正常运行。我发现测试期望ranks数组按ranks[rank] = i的方式使用,自己用printf检查preferences的每行数据看起来是正确的,不清楚问题出在哪。
我的代码如下:
// Update ranks given a new vote bool vote(int rank, string name, int ranks[]) { // TODO for (int i = 0; i < candidate_count; i++) { if (strcasecmp(name, candidates[i]) == 0) { ranks[i] = rank; rank++; return true; } } return false; } // Update preferences given one voter's ranks void record_preferences(int ranks[]) { // TODO for (int i = 0; i < candidate_count; i++) { for (int j = 0; j < candidate_count; j++) { // reverse logic when comparing ranks, because rank 0 is greater than rank 1 etc.. if(ranks[i] < ranks[j]) preferences[i][j]++; } } }
问题根源
你的vote函数完全搞反了ranks数组的定义逻辑:
题目要求ranks数组的作用是以投票优先级为下标,存储对应优先级的候选人索引——比如ranks[0]代表该投票者最支持的候选人的编号,ranks[1]代表次支持的,以此类推。但你现在的写法是ranks[i] = rank,也就是把候选人索引i作为下标,存储该候选人对应的投票优先级,这和题目定义的数组用途完全相反。
虽然你的record_preferences函数适配了这个反向的ranks数组(通过比较ranks[i] < ranks[j]来判断候选人i的优先级更高),但check50的测试用例是严格按照题目规定的ranks数组格式来校验的,所以vote函数的测试直接失败;同时首个投票者的preferences因为vote的错误初始化没通过测试,后续投票者可能因测试用例巧合或逻辑适配了反向数组,才看起来正常。
修正方案
1. 修正vote函数
把数组赋值逻辑改成题目要求的格式,同时去掉多余的rank++(vote函数仅处理单个rank的投票选择,rank递增由调用逻辑处理):
// Update ranks given a new vote bool vote(int rank, string name, int ranks[]) { for (int i = 0; i < candidate_count; i++) { if (strcasecmp(name, candidates[i]) == 0) { ranks[rank] = i; // 以优先级rank为下标,存储对应的候选人索引i return true; } } return false; }
2. 修正record_preferences函数
因为ranks数组逻辑改回了正确格式,需要调整preferences的统计逻辑,这里提供两种高效写法:
写法一:利用优先级顺序直接统计
// Update preferences given one voter's ranks void record_preferences(int ranks[]) { for (int i = 0; i < candidate_count; i++) { // 当前优先级i对应的候选人 int top_candidate = ranks[i]; // 遍历所有优先级低于i的候选人 for (int j = i + 1; j < candidate_count; j++) { int lower_candidate = ranks[j]; // 标记当前投票者认为top_candidate比lower_candidate更优 preferences[top_candidate][lower_candidate]++; } } }
这个写法直接利用rank的顺序(0是最高优先级),每个高优先级的候选人都比所有低优先级的候选人更优,逻辑清晰且高效。
写法二:通过查找优先级比较
// 辅助函数:根据候选人索引获取其对应的投票优先级 int get_candidate_rank(int ranks[], int candidate) { for (int k = 0; k < candidate_count; k++) { if (ranks[k] == candidate) { return k; } } return candidate_count; // 返回一个比所有优先级都大的值,表示未找到 } // Update preferences given one voter's ranks void record_preferences(int ranks[]) { for (int i = 0; i < candidate_count; i++) { int rank_i = get_candidate_rank(ranks, i); for (int j = 0; j < candidate_count; j++) { int rank_j = get_candidate_rank(ranks, j); // 如果候选人i的优先级比j高(rank_i更小) if (rank_i < rank_j) { preferences[i][j]++; } } } }
这个写法更直观,通过辅助函数获取每个候选人的优先级,再比较大小统计偏好关系。
验证
修正后的代码符合题目对ranks数组的定义,check50的测试用例可以正常通过,同时preferences数组的统计逻辑也完全正确。
内容的提问来源于stack exchange,提问作者Daniel Karcz

