这是用户在 2024-11-28 21:19 为 https://cs50.harvard.edu/x/2024/psets/3/runoff/ 保存的双语快照页面,由 沉浸式翻译 提供双语支持。了解如何保存?

Runoff 径流

Problem to Solve 要解决的问题

You already know about plurality elections, which follow a very simple algorithm for determining the winner of an election: every voter gets one vote, and the candidate with the most votes wins.
您已经了解了复数选举,它采用一种非常简单的算法来确定选举的获胜者:每个选民投一票,得票最多的候选人获胜。

But the plurality vote does have some disadvantages. What happens, for instance, in an election with three candidates, and the ballots below are cast?
但多数票确实有一些缺点。例如,在有三名候选人的选举中,下面的选票投出后会发生什么情况?

Five ballots, tie betweeen Alice and Bob

A plurality vote would here declare a tie between Alice and Bob, since each has two votes. But is that the right outcome?
在这里,多数票将宣布爱丽丝和鲍勃之间的票数相同,因为每个人都有两票。但这是正确的结果吗?

There’s another kind of voting system known as a ranked-choice voting system. In a ranked-choice system, voters can vote for more than one candidate. Instead of just voting for their top choice, they can rank the candidates in order of preference. The resulting ballots might therefore look like the below.
还有一种投票系统被称为排序选择投票系统。在排序选择投票系统中,选民可以投票给不止一位候选人。他们可以按照喜好对候选人进行排序,而不是只投票给自己的首选。因此,产生的选票可能如下所示。

Five ballots, with ranked preferences

Here, each voter, in addition to specifying their first preference candidate, has also indicated their second and third choices. And now, what was previously a tied election could now have a winner. The race was originally tied between Alice and Bob, so Charlie was out of the running. But the voter who chose Charlie preferred Alice over Bob, so Alice could here be declared the winner.
在这里,每位选民除了指明自己的第一首选候选人外,还指明了自己的第二和第三选择。现在,原本打成平手的选举也有了赢家。这场选举原本在爱丽丝和鲍勃之间打成平手,所以查理出局了。但选择查理的选民更喜欢爱丽丝,而不是鲍勃,因此爱丽丝可以被宣布为获胜者。

Ranked choice voting can also solve yet another potential drawback of plurality voting. Take a look at the following ballots.
排序选择投票还能解决复数投票的另一个潜在缺点。请看以下选票。

Nine ballots, with ranked preferences

Who should win this election? In a plurality vote where each voter chooses their first preference only, Charlie wins this election with four votes compared to only three for Bob and two for Alice. But a majority of the voters (5 out of the 9) would be happier with either Alice or Bob instead of Charlie. By considering ranked preferences, a voting system may be able to choose a winner that better reflects the preferences of the voters.
谁应该赢得这次选举?在复数投票中,每个选民只选择自己的第一选择,查理以 4 票获胜,而鲍勃只有 3 票,爱丽丝只有 2 票。但大多数投票者(9 人中的 5 人)会更喜欢爱丽丝或鲍勃,而不是查理。通过考虑排序偏好,投票系统也许能选出更能反映投票人偏好的获胜者。

One such ranked choice voting system is the instant runoff system. In an instant runoff election, voters can rank as many candidates as they wish. If any candidate has a majority (more than 50%) of the first preference votes, that candidate is declared the winner of the election.
其中一种排序选择投票系统是即时决胜投票系统。在即时决胜选举中,选民可以对任意多名候选人进行排序。如果任何候选人获得多数(超过 50%)的第一选择票,则宣布该候选人获胜。

If no candidate has more than 50% of the vote, then an “instant runoff” occurrs. The candidate who received the fewest number of votes is eliminated from the election, and anyone who originally chose that candidate as their first preference now has their second preference considered. Why do it this way? Effectively, this simulates what would have happened if the least popular candidate had not been in the election to begin with.
如果没有候选人获得 50%以上的选票,则进行 "即时决选"。得票最少的候选人将被淘汰出局,而原本将该候选人作为第一选择的人,现在将考虑其第二选择。为什么要这样做呢?实际上,这是在模拟如果最不受欢迎的候选人没有参加选举的情况。

The process repeats: if no candidate has a majority of the votes, the last place candidate is eliminated, and anyone who voted for them will instead vote for their next preference (who hasn’t themselves already been eliminated). Once a candidate has a majority, that candidate is declared the winner.
过程重复:如果没有候选人获得过半数选票,最后一名候选人将被淘汰,投票给他们的人将转而投票给他们的下一个选择(尚未被淘汰的人)。一旦有候选人获得多数票,就宣布该候选人获胜。

Sounds a bit more complicated than a plurality vote, doesn’t it? But it arguably has the benefit of being an election system where the winner of the election more accurately represents the preferences of the voters. In a file called runoff.c in a folder called runoff, create a program to simulate a runoff election.
听起来比多数票要复杂一些,不是吗?但可以说,这种选举制度的好处是,选举的获胜者能更准确地代表选民的偏好。在名为runoff.c文件夹下的runoff文件中,创建一个模拟决胜选举的程序。

Demo 演示

Distribution Code 分发代码

Download the distribution code
下载分发代码

Log into cs50.dev, click on your terminal window, and execute cd by itself. You should find that your terminal window’s prompt resembles the below:
登录 cs50.dev,单击终端窗口,执行 cd 本身。你会发现终端窗口的提示如下:

$

Next execute 下一步执行

wget https://cdn.cs50.net/2023/fall/psets/3/runoff.zip

in order to download a ZIP called runoff.zip into your codespace.
以便将名为 runoff.zip 的 ZIP 下载到您的代码空间。

Then execute 然后执行

unzip runoff.zip

to create a folder called runoff. You no longer need the ZIP file, so you can execute
创建一个名为 runoff 的文件夹。您不再需要 ZIP 文件,因此可以执行

rm runoff.zip

and respond with “y” followed by Enter at the prompt to remove the ZIP file you downloaded.
并在提示符下回复 "y",然后回车,以删除下载的 ZIP 文件。

Now type 现在键入

cd runoff

followed by Enter to move yourself into (i.e., open) that directory. Your prompt should now resemble the below.
然后按 Enter 键,进入(即打开)该目录。现在您的提示符应该如下所示。

runoff/ $

If all was successful, you should execute
如果一切顺利,您应该执行

ls

and see a file named runoff.c. Executing code runoff.c should open the file where you will type your code for this problem set. If not, retrace your steps and see if you can determine where you went wrong!
并看到一个名为 runoff.c 的文件。执行 code runoff.c,应该会打开该文件,您将在其中键入本问题集的代码。如果没有,请回溯您的步骤,看看是否能确定您在哪里出错!

Understand the code in runoff.c
理解 runoff.c 中的代码

Whenever you’ll extend the functionality of existing code, it’s best to be sure you first understand it in its present state.
无论何时您要扩展现有代码的功能,最好先确保您了解它的当前状态。

Look at the top of runoff.c first. Two constants are defined: MAX_CANDIDATES for the maximum number of candidates in the election, and MAX_VOTERS for the maximum number of voters in the election.
先看 runoff.c 的顶部。这里定义了两个常量MAX_CANDIDATES 表示选举中候选人的最大数量,MAX_VOTERS 表示选举中选民的最大数量。

// Max voters and candidates
#define MAX_VOTERS 100
#define MAX_CANDIDATES 9

Notice that MAX_CANDIDATES is used to size an array, candidates.
请注意,MAX_CANDIDATES 用于确定数组 candidates 的大小。

// Array of candidates
candidate candidates[MAX_CANDIDATES];

candidates is an array of candidates. In runoff.c a candidate is a struct. Every candidate has a string field for their name, an int representing the number of votes they currently have, and a bool value called eliminated that indicates whether the candidate has been eliminated from the election. The array candidates will keep track of all of the candidates in the election.
candidates 是一个由 candidate 组成的数组。在 runoff.c 中,candidate 是一个 struct 。每个候选人都有一个字符串字段表示他们的姓名,一个整数表示他们当前拥有的票数、以及一个名为 eliminatedbool 值,表示候选人是否已被淘汰出局。数组 candidates 将跟踪选举中的所有候选人。

// Candidates have name, vote count, eliminated status
typedef struct
{
    string name;
    int votes;
    bool eliminated;
}
candidate;

Now you can better understand preferences, the two-dimensional array. The array preferences[i] will represent all of the preferences for voter number i. The integer, preferences[i][j], will store the index of the candidate, from the candidates array, who is the jth preference for voter i.
现在您可以更好地理解二维数组 preferences 了。数组 preferences[i] 将代表编号为 i 的选民的所有偏好。整數 preferences[i][j] 將儲存 candidates 陣列中的候選人索引,該候選人是選民 j 的第 i 個偏好。

// preferences[i][j] is jth preference for voter i
int preferences[MAX_VOTERS][MAX_CANDIDATES];

The program also has two global variables: voter_count and candidate_count.
程序中还有两个全局变量:voter_countcandidate_count.

// Numbers of voters and candidates
int voter_count;
int candidate_count;

Now onto main. Notice that after determining the number of candidates and the number of voters, the main voting loop begins, giving every voter a chance to vote. As the voter enters their preferences, the vote function is called to keep track of all of the preferences. If at any point, the ballot is deemed to be invalid, the program exits.
现在开始main。请注意,在确定候选人数和投票人数后,主投票循环就开始了,每个投票者都有机会投票。当投票者输入他们的偏好时,vote 函数将被调用,以跟踪所有的偏好。如果在任何时候,选票被视为无效,程序就会退出。

Once all of the votes are in, another loop begins: this one’s going to keep looping through the runoff process of checking for a winner and eliminating the last place candidate until there is a winner.
一旦所有选票都投完后,另一个循环就开始了:这个循环将不断循环检查获胜者和淘汰最后一名候选人,直到产生获胜者为止。

The first call here is to a function called tabulate, which should look at all of the voters’ preferences and compute the current vote totals, by looking at each voter’s top choice candidate who hasn’t yet been eliminated. Next, the print_winner function should print out the winner if there is one; if there is, the program is over. But otherwise, the program needs to determine the fewest number of votes anyone still in the election received (via a call to find_min). If it turns out that everyone in the election is tied with the same number of votes (as determined by the is_tie function), the election is declared a tie; otherwise, the last-place candidate (or candidates) is eliminated from the election via a call to the eliminate function.
这里的第一次调用是调用一个名为 tabulate 的函数,该函数应查看所有投票人的偏好,并通过查看每位投票人的首选候选人(尚未被淘汰)计算出当前的总票数。接下来,print_winner函数应该打印出获胜者(如果有的话);如果有的话,程序就结束了。否则,程序需要确定仍在选举中的任何人获得的最少票数(通过调用 find_min 函数)。如果结果显示选举中的每个人都以相同的票数并列(由 is_tie 函数确定),则宣布选举并列;否则,通过调用 eliminate 函数,最后一名(或多名)候选人将被淘汰出局。

If you look a bit further down in the file, you’ll see that the rest of the functions—vote, tabulate, print_winner, find_min, is_tie, and eliminate—are all left to up to you to complete! You should only modify these functions in runoff.c, though you may #include additional header files atop runoff.c if you’d like
如果您在文件中再往下看一点,就会发现其余的函数--vote, tabulateprint_winner, find_min, is_tie, 和 eliminate 都由您来完成!您只需修改 runoff.c 中的这些函数,当然,如果您愿意,也可以 #include 在 runoff.c 顶部的其他头文件

Hints 提示

Click the below toggles to read some advice!
点击下面的切换按钮,阅读一些建议!

Complete the vote function
完成 vote 功能

Complete the vote function.
完成 vote 功能。

  • The function takes three arguments: voter, rank, and name.
    该函数需要三个参数:voter, rank, 和 name.
  • If name is a match for the name of a valid candidate, then you should update the global preferences array to indicate that the voter voter has that candidate as their rank preference. Keep in mind 0 is the first preference, 1 is the second preference, etc. You may assume that no two candidates will have the same name.
    如果 name 与有效候选人的姓名匹配,则应更新全局首选项数组,以表明投票人 voter 将该候选人作为其 rank 首选项。请记住,0 是第一优先选择,1 是第二优先选择,等等。您可以假设没有两个候选人的名字相同。
  • If the preference is successfully recorded, the function should return true. The function should return false otherwise. Consider, for instance, when name is not the name of one of the candidates.
    如果首选项被成功记录,函数应返回 true。否则,函数应返回 false。例如,当 name 不是候选人的姓名时。

As you write your code, consider these hints:
在编写代码时,请考虑这些提示:

  • Recall that candidate_count stores the number of candidates in the election.
    请注意,candidate_count存储的是选举中候选人的数量。
  • Recall that you can use strcmp to compare two strings.
    回顾一下,您可以使用 strcmp 来比较两个字符串。
  • Recall that preferences[i][j] stores the index of the candidate who is the jth ranked preference for the ith voter.
    回想一下,preferences[i][j]存储的是j位投票人的i次排序的候选人的索引。
Complete the tabulate function
完成 tabulate 功能

Complete the tabulate function.
完成 tabulate 函数。

  • The function should update the number of votes each candidate has at this stage in the runoff.
    函数应更新每位候选人在决胜阶段的 票数
  • Recall that at each stage in the runoff, every voter effectively votes for their top-preferred candidate who has not already been eliminated.
    回顾一下,在决选的每个阶段,每位选民实际上都会投票给自己最中意的、尚未被淘汰的候选人。

As you write your code, consider these hints:
在编写代码时,请考虑这些提示:

  • Recall that voter_count stores the number of voters in the election and that, for each voter in our election, we want to count one ballot.
    回想一下,voter_count 存储了选举中的选民人数,而对于选举中的每个选民,我们都希望计算一张选票。
  • Recall that for a voter i, their top choice candidate is represented by preferences[i][0], their second choice candidate by preferences[i][1], etc.
    回顾一下,对于投票人i来说,其首选候选人由首选项[i][0]表示,其次选候选人由首选项[i][1]表示,等等。
  • Recall that the candidate struct has a field called eliminated, which will be true if the candidate has been eliminated from the election.
    回想一下,candidatestruct 有一个名为 eliminated 的字段,如果候选人已被淘汰出局,该字段将为 true
  • Recall that the candidate struct has a field called votes, which you’ll likely want to update for each voter’s preferred candidate.
    回想一下,candidatestruct 有一个名为 votes 的字段,您很可能要为每个投票者的首选候选人更新该字段。
  • Recall that once you’ve cast a vote for a voter’s first non-eliminated candidate, you’ll want to stop there, not continue down their ballot. You can break out of a loop early using break inside of a conditional.
    回想一下,一旦你给投票人的第一位未被淘汰的候选人投了一票,你就会想就此打住,而不是继续给他们投票。您可以使用条件中的 break 提前跳出循环。
Complete the print_winner function
完成 print_winner 函数

Complete the print_winner function.
完成 print_winner 函数。

  • If any candidate has more than half of the vote, their name should be printed and the function should return true.
    如果任何候选人的得票数超过半数,则应打印其姓名,函数应返回 true
  • If nobody has won the election yet, the function should return false.
    如果还没有人赢得选举,函数应返回 false

As you write your code, consider this hint:
在编写代码时,请考虑以下提示:

  • Recall that voter_count stores the number of voters in the election. Given that, how would you express the number of votes needed to win the election?
    回想一下,voter_count 存储了选举中的选民人数。鉴于此,您将如何表示赢得选举所需的票数?
Complete the find_min function
完成 find_min 函数

Complete the find_min function.
完成 find_min 函数。

  • The function should return the minimum vote total for any candidate who is still in the election.
    该函数应返回任何仍在选举中的候选人的最低总票数。

As you write your code, consider this hint:
在编写代码时,请考虑以下提示:

  • You’ll likely want to loop through the candidates to find the one who is both still in the election and has the fewest number of votes. What information should you keep track of as you loop through the candidates?
    您可能希望循环浏览候选人,找出仍在选举中且得票数最少的候选人。在循环浏览候选人的过程中,您需要跟踪哪些信息?
Complete the is_tie function
完成 is_tie 函数

Complete the is_tie function.
完成 is_tie 函数。

  • The function takes an argument min, which will be the minimum number of votes that anyone in the election currently has.
    该函数接收一个参数 min,它将是选举中任何人当前拥有的最少票数。
  • The function should return true if every candidate remaining in the election has the same number of votes, and should return false otherwise.
    如果选举中剩下的每个候选人的票数相同,函数应返回 true ;否则应返回 false

As you write your code, consider this hint:
在编写代码时,请考虑以下提示:

  • Recall that a tie happens if every candidate still in the election has the same number of votes. Note, too, that the is_tie function takes an argument min, which is the smallest number of votes any candidate currently has. How might you use min to determine if the election is a tie (or, conversely, not a tie)?
    回想一下,如果仍在选举中的每位候选人的得票数相同,就会出现票数相同的情况。还要注意的是,is_tie 函数需要一个参数 min ,即任何候选人当前拥有的最小票数。您可以如何使用 min 来确定选举是否平局(或者相反,是否平局)?
Complete the eliminate function
完成 消除函数

Complete the eliminate function.
完成 eliminate 功能。

  • The function takes an argument min, which will be the minimum number of votes that anyone in the election currently has.
    该函数接收一个参数 min,它将是选举中任何人当前拥有的最少票数。
  • The function should eliminate the candidate (or candidates) who have min number of votes.
    该函数应淘汰得票数最少的候选人。

Walkthrough 演练

How to Test 如何测试

Be sure to test your code to make sure it handles…
请务必测试您的代码,以确保它能处理...

  • An election with any number of candidate (up to the MAX of 9)
    候选人人数不限(最多最大9)。
  • Voting for a candidate by name
    点名投票支持候选人
  • Invalid votes for candidates who are not on the ballot
    对未列入选票的候选人投无效票
  • Printing the winner of the election if there is only one
    如果只有一名选举获胜者,则打印获胜者名单
  • Not eliminating anyone in the case of a tie between all remaining candidates
    在所有剩余候选人票数相同的情况下,不淘汰任何人

Correctness 正确性

check50 cs50/problems/2024/x/runoff

Style 风格

style50 runoff.c

How to Submit 如何提交

submit50 cs50/problems/2024/x/runoff