CS50 Tideman程序运行正常,但check50表示相反

时间:2020-06-24 04:27:29

标签: c multidimensional-array cs50 adjacency-matrix

我参加了哈佛大学CS50入门课程,被困在某个作业中(完成了潮汐选举模拟的代码),并且在提交作业之前,可以通过在哈佛大学中运行check50来检查代码的正确性CS50 IDE

基于我已经运行的多个测试,我的程序运行正常,但是每次我运行check50时,都会返回一条错误消息:

  • :( lock_pairs如果创建循环则跳过最后一对
    • 原因:lock_pairs未正确锁定所有非周期性对

edit:此链接https://cs50.harvard.edu/x/2020/psets/3/tideman/

中包含有关该程序如何工作的完整详细信息。

我尝试了多种测试,从简单的测试(三个候选者的5票)到更复杂的测试(四个候选者的9票创建了一个小的中间周期和最后一个周期),我的代码可以正常工作。

如果有人能找到我代码逻辑中的错误,甚至可能会缩短我的代码的方法,将受到高度赞赏,因为在我看来,它看起来非常混乱XD

我的主要问题在于这个lock_pairs()函数

// Lock pairs into the candidate graph in order, without creating cycles
void lock_pairs(void)
{
    // TODO

    //initialize an array that could tell whether a pair used to be locked or not
    bool wasLocked[MAX][MAX];

    //clear the wasLocked array
    for (int i = 0; i < MAX; i++)
    {
        for (int j = 0; j < MAX; j++)
        {
            wasLocked[i][j] = false;
        }
    }

    //loop through each pair
    for (int i = 0; i < pair_count; i++)
    {
        //temporarily set current pair to true on locked array
        locked[pairs[i].winner][pairs[i].loser] = true;

        //permanently set current pair to true on wasLocked array
        wasLocked[pairs[i].winner][pairs[i].loser] = true;

        //pointee is the loser in the current pair
        int pointee = pairs[i].loser;
        bool checkCycle = true;

        while (checkCycle == true)
        {
            for (int j = 0; j < pair_count; j++)
            {
                //if the current pointee is one of the winners
                if (pointee == pairs[j].winner)
                {
                    //if the pointee and pointee's loser pair is not locked in
                    if (locked[pairs[j].winner][pairs[j].loser] == false)
                    {
                        //And if the pointee and pointee's loser pair was never locked in in the first place
                        if (wasLocked[pairs[j].winner][pairs[j].loser] == false)
                        {
                            checkCycle = false;
                            break;
                        }
                        //else skip this pair and restart the cycle looking for another pointee winner
                    }

                    //if the pointee and pointee's loser pair is already locked in
                    else if (locked[pairs[j].winner][pairs[j].loser] == true)
                    {
                        //if it does create a cycle, don't lock in the current winning pair
                        if (pairs[j].loser == pairs[i].winner)
                        {
                            locked[pairs[i].winner][pairs[i].loser] = false;
                            checkCycle = false;
                            break;
                        }

                        //if not sure if it creates a cycle, follow the path of pointees until we get to a cycle or not
                        else
                        {
                            pointee = pairs[j].loser;
                            break;
                        }
                    }
                }

                //if the pointee is not one of the winners and we have reached the end of the loop without breaking
                //break out of checkCycle loop to officially lock in the winning pair
                else if (j == pair_count - 1)
                {
                    checkCycle = false;
                }
            }
        }
    }

    return;
}

这是完整的代码

#include <cs50.h>
#include <stdio.h>
#include <string.h>

// Max number of candidates
#define MAX 9

// preferences[i][j] is number of voters who prefer i over j
int preferences[MAX][MAX];

// locked[i][j] means i is locked in over j
bool locked[MAX][MAX];

// Each pair has a winner, loser
typedef struct
{
    int winner;
    int loser;
}
pair;

// Array of candidates
string candidates[MAX];
pair pairs[MAX * (MAX - 1) / 2];

int pair_count;
int candidate_count;

// Function prototypes
bool vote(int rank, string name, int ranks[]);
void record_preferences(int ranks[]);
void add_pairs(void);
void sort_pairs(void);
void lock_pairs(void);
void print_winner(void);

int main(int argc, string argv[])
{
    // Check for invalid usage
    if (argc < 2)
    {
        printf("Usage: tideman [candidate ...]\n");
        return 1;
    }

    // Populate array of candidates
    candidate_count = argc - 1;
    if (candidate_count > MAX)
    {
        printf("Maximum number of candidates is %i\n", MAX);
        return 2;
    }
    for (int i = 0; i < candidate_count; i++)
    {
        candidates[i] = argv[i + 1];
    }

    // Clear graph of locked in pairs
    for (int i = 0; i < candidate_count; i++)
    {
        for (int j = 0; j < candidate_count; j++)
        {
            locked[i][j] = false;
        }
    }

    pair_count = 0;
    int voter_count = get_int("Number of voters: ");

    // Query for votes
    for (int i = 0; i < voter_count; i++)
    {
        // ranks[i] is voter's ith preference
        int ranks[candidate_count];

        // Query for each rank
        for (int j = 0; j < candidate_count; j++)
        {
            string name = get_string("Rank %i: ", j + 1);
            vote(j, name, ranks);

            if (!vote(j, name, ranks))
            {
                printf("Invalid vote.\n");
                return 3;
            }
        }

        record_preferences(ranks);

        printf("\n");
    }

    add_pairs();
    sort_pairs();
    lock_pairs();
    print_winner();
    return 0;
}

// Update ranks given a new vote
//note: this function is called depending on the amount of candidates and the array of ranks change per voter
bool vote(int rank, string name, int ranks[])
{
    // TODO

    //loops through candidates
    for (int i = 0; i < candidate_count; i++)
    {
        //once we find the corresponding candidate given the name, then we put the index of that candidate into the chosen rank of
        //the current voter
        if (strcmp(name, candidates[i]) == 0)
        {
            ranks[rank] = i;
            return true;
        }
    }

    return false;
}

// Update preferences given one voter's ranks
void record_preferences(int ranks[])
{
    // TODO

    //basically this will update preferences wherein the highest rank will dominate in votes over the lower ranks
    for (int i = 0; i < candidate_count; i++)
    {
        for (int j = i + 1; j < candidate_count; j++)
        {
            preferences[ranks[i]][ranks[j]]++;
        }
    }

    return;
}

// Record pairs of candidates where one is preferred over the other
void add_pairs(void)
{
    // TODO

    for (int i = 0; i < candidate_count; i++)
    {
        for (int j = 0; j < candidate_count; j++)
        {
            if (preferences[i][j] > 0)
            {
                //check for ties, if ties are found then skip
                if (preferences[i][j] != preferences[j][i])
                {
                    //check for a winning pair, then add to pair array
                    if (preferences[i][j] > preferences[j][i])
                    {
                        pairs[pair_count].winner = i;
                        pairs[pair_count].loser = j;
                        pair_count++;
                    }
                }
            }
        }
    }

    return;
}

// Sort pairs in decreasing order by strength of victory
void sort_pairs(void)
{
    // TODO

    //set the index for where the greatest value would be placed if found
    int index = 0;

    bool is_sorted = false;
    while (is_sorted == false)
    {
        for (int i = index; i < pair_count; i++)
        {
            //this makes it so that when we detect an increase of index, we restart the loop to find the next greatest value
            int indexPast = index;

            //set 'a' to be the current greatest value to compare
            int a = preferences[pairs[i].winner][pairs[i].loser];

            for (int j = i + 1; j < pair_count; j++)
            {
                //preference 'b' would be compared to 'a'
                int b = preferences[pairs[j].winner][pairs[j].loser];

                //if 'a' has made it through the loop without breaking
                if (j == pair_count - 1)
                {
                    if (a < b)
                    {
                        pair temp = pairs[index];
                        pairs[index] = pairs[j];
                        pairs[j] = temp;
                        index++;
                        break;
                    }
                    else if (a >= b)
                    {
                        pair temp = pairs[index];
                        pairs[index] = pairs[i];
                        pairs[i] = temp;
                        index++;
                        break;
                    }
                }

                //'b' is greater than 'a', compare the next value with 'b' being our current greatest value
                else if (a < b)
                {
                    break;
                }
            }

            //if we have noticed a change in index, restart the whole while loop to find the next greatest value
            if (index > indexPast)
            {
                break;
            }
        }

        //if 'a' is the last value in the array and the loop hasnt been broken, the array is now sorted with 'a' being the lowest value
        if (index >= pair_count - 1)
        {
            is_sorted = true;
        }
    }

    return;
}

// Lock pairs into the candidate graph in order, without creating cycles
void lock_pairs(void)
{
    // TODO

    //initialize an array that could tell whether a pair used to be locked or not
    bool wasLocked[MAX][MAX];

    //clear the wasLocked array
    for (int i = 0; i < MAX; i++)
    {
        for (int j = 0; j < MAX; j++)
        {
            wasLocked[i][j] = false;
        }
    }

    //loop through each pair
    for (int i = 0; i < pair_count; i++)
    {
        //temporarily set current pair to true on locked array
        locked[pairs[i].winner][pairs[i].loser] = true;

        //permanently set current pair to true on wasLocked array
        wasLocked[pairs[i].winner][pairs[i].loser] = true;

        //pointee is the loser in the current pair
        int pointee = pairs[i].loser;
        bool checkCycle = true;

        while (checkCycle == true)
        {
            for (int j = 0; j < pair_count; j++)
            {
                //if the current pointee is one of the winners
                if (pointee == pairs[j].winner)
                {
                    //if the pointee and pointee's loser pair is not locked in
                    if (locked[pairs[j].winner][pairs[j].loser] == false)
                    {
                        //And if the pointee and pointee's loser pair was never locked in in the first place
                        if (wasLocked[pairs[j].winner][pairs[j].loser] == false)
                        {
                            checkCycle = false;
                            break;
                        }
                        //else skip this pair and restart the cycle looking for another pointee winner
                    }

                    //if the pointee and pointee's loser pair is already locked in
                    else if (locked[pairs[j].winner][pairs[j].loser] == true)
                    {
                        //if it does create a cycle, don't lock in the current winning pair
                        if (pairs[j].loser == pairs[i].winner)
                        {
                            locked[pairs[i].winner][pairs[i].loser] = false;
                            checkCycle = false;
                            break;
                        }

                        //if not sure if it creates a cycle, follow the path of pointees until we get to a cycle or not
                        else
                        {
                            pointee = pairs[j].loser;
                            break;
                        }
                    }
                }

                //if the pointee is not one of the winners and we have reached the end of the loop without breaking
                //break out of checkCycle loop to officially lock in the winning pair
                else if (j == pair_count - 1)
                {
                    checkCycle = false;
                }
            }
        }
    }

    return;
}

// Print the winner of the election
void print_winner(void)
{
    // TODO

    //we loop through the locked array to find a candidate that was never locked in as a loser
    for (int i = 0; i < candidate_count; i++)
    {
        for (int j = 0; j < candidate_count; j++)
        {
            if (locked[j][i] == true)
            {
                break;
            }
            else if (j == candidate_count - 1)
            {
                //a winning candidate was found and was never locked in as a loser
                if (locked[j][i] == false)
                {
                    printf("%s\n", candidates[i]);
                    break;
                }
            }
        }
    }

    return;
}

请随时运行我的代码,并尝试其他可能破坏我的代码的检查,因为我不知道该怎么办XD

使我的代码更有效率的技巧也受到高度赞赏:)

编辑:

我的print_winner()函数曾经有错误,但是在查看@EthanMark发布的类似问题后,我可以通过将pair_count更改为候选人数来解决此问题

0 个答案:

没有答案