You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

CS50 Runoff作业C代码check50未通过,求错误定位帮助

CS50 Runoff作业错误排查求助

我的CS50第三套作业Runoff的C代码本地测试运行正常,但使用check50检测时未能通过部分测试项,具体问题:

  • tabulate函数在多候选人被淘汰、处理多轮偏好时无法生成正确票数
  • find_min函数未正确忽略已淘汰候选人

尝试调试但未解决问题,希望得到帮助找出错误原因。

代码

#include <cs50.h>
#include <stdio.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 candidate_rank = 0;

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;
        }

        if (candidate_rank < candidate_count)
        {
            candidate_rank++;
        }
    }
    return 0;
}

// Record preference if vote is valid
bool vote(int voter, int rank, string name)
{
    for (int i = 0; i < candidate_count; i++)
    {
        if (strcmp(candidates[i].name, name) == 0)
        {
            preferences[voter][rank] = i;
            return true;
        }
    }
    return false;
}

// Tabulate votes for non-eliminated candidates
void tabulate(void)
{
    for (int i = 0; i < voter_count; i++)
    {
        int preference = preferences[i][candidate_rank];
        if (!candidates[preference].eliminated)
        {
            candidates[preference].votes++;
        }
    }
}

// Print the winner of the election, if there is one
bool print_winner(void)
{
    int votes = 0;
    for (int i = 0; i < candidate_count; i++)
    {
        votes += candidates[i].votes;
    }

    for (int i = 0; i < candidate_count; i++)
    {
        if (candidates[i].votes > (float) votes / 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 votes[candidate_count];
    for (int i = 0; i < candidate_count; i++)
    {
        votes[i] = candidates[i].votes;
    }

    for (int i = 0; i < candidate_count; i++)
    {
        for (int j = 0; j < candidate_count - 1; j++)
        {
            if (votes[j] > votes[j + 1])
            {
                int x = votes[j];
                votes[j] = votes[j + 1];
                votes[j + 1] = x;
            }
        }
    }
    for (int i = 0; i < candidate_count; i++)
    {
        if (!candidates[i].eliminated)
        {
            return votes[i];
        }
    }
    return 0;
}

// Return true if the election is tied between all candidates, false otherwise
bool is_tie(int min)
{
    int votes;
    bool tied;
    for (int i = 0; i < candidate_count; i++)
    {
        if (!candidates[i].eliminated)
        {
            votes = candidates[i].votes;
        }
    }
    for (int i = 0; i < candidate_count; i++)
    {
        if (!candidates[i].eliminated)
        {
            if (votes == candidates[i].votes)
            {
                tied = true;
            }
            else
            {
                tied = false;
                i = candidate_count;
            }
        }
    }
    if (!tied)
    {
        return false;
    }
    else
    {
        return true;
    }
}

// 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)
        {
            candidates[i].eliminated = true;
        }
    }
}

check50检测结果

√ runoff.c 文件存在
√ 代码可编译
√ 给定候选人姓名时vote返回true
√ 给定无效姓名时vote返回false
√ vote正确设置第一位选民的第一偏好
√ vote正确设置第二位选民的第三偏好
√ vote正确设置选民的所有偏好
√ 所有候选人未淘汰时tabulate统计票数正确
√ 一位候选人淘汰时tabulate统计票数正确
× 多候选人被淘汰时tabulate统计票数错误
    tabulate函数未生成正确票数
× tabulate处理多轮偏好时出错
    tabulate函数未生成正确票数
√ 有人获得多数票时print_winner输出姓名
√ 有人获得多数票时print_winner返回true
√ 无人获得多数票时print_winner返回false
√ 领先者获恰好50%票数时print_winner返回false
√ find_min返回候选人的最低票数
√ 所有候选人平局时find_min返回最低票数
× find_min未忽略已淘汰候选人
    find_min未识别正确的最低票数
√ 选举平局时is_tie返回true
√ 选举非平局时is_tie返回false
√ 仅部分候选人平局时is_tie返回false
√ 部分候选人淘汰后检测平局时is_tie工作正常
√ eliminate淘汰最后一名候选人
√ eliminate淘汰平局的多名最后一名候选人
√ 部分候选人已淘汰时eliminate正常工作

错误分析与修复建议

1. tabulate函数核心错误

你用全局变量candidate_rank统一处理所有选民的偏好顺位,完全不符合 runoff 选举规则。正确逻辑是:对每个选民,从第一顺位(rank 0)开始遍历其偏好列表,找到第一个未被淘汰的候选人,为该候选人增加一票,而非所有选民共用同一个顺位。

修复后的tabulate函数:

void tabulate(void)
{
    for (int i = 0; i < voter_count; i++)
    {
        // 对每个选民,从第一偏好开始找未淘汰的候选人
        for (int j = 0; j < candidate_count; j++)
        {
            int pref_idx = preferences[i][j];
            if (!candidates[pref_idx].eliminated)
            {
                candidates[pref_idx].votes++;
                break; // 找到有效偏好后,处理下一个选民
            }
        }
    }
}

同时删除全局变量candidate_rank,以及main函数中更新该变量的代码段。

2. find_min函数错误

你先将所有候选人票数排序,再遍历候选人找未淘汰者返回对应票数,但排序后的votes数组与原candidates数组索引已不对应,导致返回错误最小值。

正确逻辑:遍历所有未被淘汰的候选人,记录其中最小票数。

修复后的find_min函数:

int find_min(void)
{
    int min_votes = voter_count; // 初始化为最大可能票数
    for (int i = 0; i < candidate_count; i++)
    {
        if (!candidates[i].eliminated && candidates[i].votes < min_votes)
        {
            min_votes = candidates[i].votes;
        }
    }
    return min_votes;
}

3. is_tie函数潜在问题

原代码中votes和tied未初始化,极端情况(所有候选人被淘汰)会导致未定义行为。修复后:

bool is_tie(int min)
{
    bool tied = true;
    int first_votes = -1;
    for (int i = 0; i < candidate_count; i++)
    {
        if (!candidates[i].eliminated)
        {
            if (first_votes == -1)
            {
                first_votes = candidates[i].votes;
            }
            else if (candidates[i].votes != first_votes)
            {
                tied = false;
                break;
            }
        }
    }
    return tied;
}

内容的提问来源于stack exchange,提问作者Aadi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.15 06:37:02