CS50决选算法中find_min函数check50检测异常问题
CS50决选选举(Runoff)算法find_min函数问题修复
正在完成CS50课程的决选选举算法开发,check50检测显示多数功能正常,但当所有候选人票数相同时,find_min函数未返回正确最小值的测试项失败。自行测试3位候选人、3位选民且每位选民投票给不同候选人的场景时,程序打印出的最小值为预期的1,也能正确识别平局,但check50仍判定该测试失败。
check50检测结果
:) runoff.c exists :) runoff compiles :) vote returns true when given name of candidate :) vote returns false when given name of invalid candidate :) vote correctly sets first preference for first voter :) vote correctly sets third preference for second voter :) vote correctly sets all preferences for voter :) tabulate counts votes when all candidates remain in election :) tabulate counts votes when one candidate is eliminated :) tabulate counts votes when multiple candidates are eliminated :) tabulate handles multiple rounds of preferences :) print_winner prints name when someone has a majority :) print_winner returns true when someone has a majority :) print_winner returns false when nobody has a majority :) print_winner returns false when leader has exactly 50% of vote :) find_min returns minimum number of votes for candidate :( find_min returns minimum when all candidates are tied find_min did not identify correct minimum :) find_min ignores eliminated candidates :) is_tie returns true when election is tied :) is_tie returns false when election is not tied :) is_tie returns false when only some of the candidates are tied :) is_tie detects tie after some candidates have been eliminated
原代码
#include <cs50.h> #include <stdio.h> #include <stdlib.h> #include <string.h> // Max voters and candidates #define MAX_VOTERS 100 #define MAX_CANDIDATES 9 // preferences[i][j] is jth preference for voter i int preferences[MAX_VOTERS][MAX_CANDIDATES]; // Candidates have name, vote count, eliminated status typedef struct { string name; int votes; bool eliminated; } candidate; // Array of candidates candidate candidates[MAX_CANDIDATES]; // Numbers of voters and candidates int voter_count; int candidate_count; // Function prototypes bool vote(int voter, int rank, string name); void tabulate(void); bool print_winner(void); int find_min(void); bool is_tie(int min); void eliminate(int min); int main(int argc, string argv[]) { // Check for invalid usage if (argc < 2) { printf("Usage: runoff [candidate ...]\n"); return 1; } // Populate array of candidates candidate_count = argc - 1; if (candidate_count > MAX_CANDIDATES) { printf("Maximum number of candidates is %i\n", MAX_CANDIDATES); return 2; } for (int i = 0; i < candidate_count; i++) { candidates[i].name = argv[i + 1]; candidates[i].votes = 0; candidates[i].eliminated = false; } voter_count = get_int("Number of voters: "); if (voter_count > MAX_VOTERS) { printf("Maximum number of voters is %i\n", MAX_VOTERS); return 3; } // Keep querying for votes for (int i = 0; i < voter_count; i++) { // Query for each rank for (int j = 0; j < candidate_count; j++) { string name = get_string("Rank %i: ", j + 1); // Record vote, unless it's invalid if (!vote(i, j, name)) { printf("Invalid vote.\n"); return 4; } } printf("\n"); } // Keep holding runoffs until winner exists while (true) { // Calculate votes given remaining candidates tabulate(); // Check if election has been won bool won = print_winner(); if (won) { break; } // Eliminate last-place candidates int min = find_min(); bool tie = is_tie(min); // If tie, everyone wins if (tie) { for (int i = 0; i < candidate_count; i++) { if (!candidates[i].eliminated) { printf("%s\n", candidates[i].name); } } break; } // Eliminate anyone with minimum number of votes eliminate(min); // Reset vote counts back to zero for (int i = 0; i < candidate_count; i++) { candidates[i].votes = 0; } } return 0; } // Record preference if vote is valid bool vote(int voter, int rank, string name) { int cmp; for (int i = 0; i < candidate_count; i++) { cmp = strcmp(candidates[i].name, name); if (cmp == 0) { preferences[voter][rank] = i; return true; } } return false; } // Tabulate votes for non-eliminated candidates void tabulate(void) { int cont; for (int i = 0; i < voter_count; i++) { cont = 0; while (candidates[preferences[i][cont]].eliminated) { cont++; } candidates[preferences[i][cont]].votes++; } return; } // Print the winner of the election, if there is one bool print_winner(void) { for (int i = 0; i < candidate_count; i++) { if (candidates[i].votes > (voter_count / 2)) { printf("%s\n", candidates[i].name); return true; } } return false; } // Return the minimum number of votes any remaining candidate has int find_min(void) { int min = candidate_count + 1; int max = 0; for (int i = 0; i < candidate_count; i++) { if (candidates[i].eliminated) { printf("%s eliminado\n", candidates[i].name); } if (!candidates[i].eliminated) { if (candidates[i].votes < min) { min = candidates[i].votes; } } } printf("%i", min); return min; } // Return true if the election is tied between all candidates, false otherwise bool is_tie(int min) { int cont = 0; int max = 0; for (int i = 0; i < candidate_count; i++) { if (candidates[i].votes > max) { max = candidates[i].votes; } } if (max == min) return true; return false; } // Eliminate the candidate (or candidates) in last place void eliminate(int min) { for (int i = 0; i < candidate_count; i++) { if (candidates[i].votes == min) { candidates[i].eliminated = true; } } return; }
问题分析与修复
问题根源
check50测试失败的核心原因是find_min函数中添加的调试打印语句干扰了测试的输出判断:
- 函数内的
printf("%s eliminado\n", candidates[i].name);和printf("%i", min);会向标准输出打印额外内容,而check50是通过捕获程序的标准输出来验证功能正确性的,这些额外输出会导致测试逻辑误判。 - 虽然本地测试时能看到正确的最小值,但check50会将这些额外输出视为程序的异常输出,从而判定测试失败。
修复步骤
- 删除调试打印语句:移除
find_min函数中的所有printf语句,只保留核心逻辑。 - 优化初始值(可选但更严谨):将min的初始值从
candidate_count + 1改为第一个未被淘汰候选人的票数,避免极端情况下初始值不合理的问题。
修复后的find_min函数:
// Return the minimum number of votes any remaining candidate has int find_min(void) { // 初始化min为第一个未被淘汰候选人的票数 int min = -1; for (int i = 0; i < candidate_count; i++) { if (!candidates[i].eliminated) { min = candidates[i].votes; break; } } // 遍历所有未被淘汰的候选人,找到最小票数 for (int i = 0; i < candidate_count; i++) { if (!candidates[i].eliminated && candidates[i].votes < min) { min = candidates[i].votes; } } return min; }
验证
修复后重新运行check50,该测试项即可通过。本地测试时若需要调试,可临时添加打印语句,但提交前务必删除,避免干扰测试。
内容的提问来源于stack exchange,提问作者m4theus
相关产品推荐
相关产品推荐

