我参加了哈佛大学CS50入门课程,被困在某个作业中(完成了潮汐选举模拟的代码),并且在提交作业之前,可以通过在哈佛大学中运行check50来检查代码的正确性CS50 IDE
基于我已经运行的多个测试,我的程序运行正常,但是每次我运行check50时,都会返回一条错误消息:
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更改为候选人数来解决此问题