Cs50 Tideman Solution Better -
Algorithmic Implementation of the Tideman Voting System
A Comprehensive Analysis of the CS50 Solution
High-level algorithm (functions)
-
bool vote(int rank, char *name, int ranks[])
- Map voter choice name to candidate index.
- Return false if invalid name; otherwise set ranks[rank] and return true.
-
void record_preferences(int ranks[])
- For each i < j: preferences[ranks[i]][ranks[j]]++
-
void add_pairs(void)
- For every i != j:
- if preferences[i][j] > preferences[j][i], add i, j, preferences[i][j] - preferences[j][i] to pairs[].
- For every i != j:
-
void sort_pairs(void)
- Sort pairs[] in descending order by margin. Use qsort or selection sort for clarity.
-
bool creates_cycle(int winner, int loser)
- Recursively (or with DFS) check if adding edge winner->loser would create a path from loser back to winner.
- Base: if loser == winner return true.
- For each k: if locked[loser][k] and creates_cycle(winner, k) return true.
- Return false otherwise.
-
void lock_pairs(void)
- For each pair in sorted order:
- if (!creates_cycle(pair.winner, pair.loser)) locked[winner][loser] = true;
- For each pair in sorted order:
-
void print_winner(void)
- Find candidate i where no j has locked[j][i] == true.
- Print candidate name.
1. Vote and Preferences Arrays
You’ll have:
preferences[i][j]= number of voters who prefer candidateiover candidatejlocked[i][j]= true if there’s a locked edge fromitoj
The vote function updates the ranks array for each voter. Then record_preferences uses those ranks to increment preferences[i][j] for every i ranked higher than j.
7. Why This Solution is Elegant
The recursive is_path approach is the clearest expression of cycle detection. It directly mirrors the definition: "Adding edge X→Y creates a cycle if Y can already reach X."
Once you internalize this, the Tideman problem transforms from an impossible puzzle into a manageable task.
The Helper Function: will_create_cycle
We will write a helper that answers: "Starting from the loser, can I eventually reach the winner using existing locked edges?" Cs50 Tideman Solution
If yes → cycle → don’t lock. If no → safe to lock.
The Problem in Plain English
We have an election. Voters rank candidates. The Tideman method (a ranked-pair voting system) works like this:
- Vote: Record every voter’s preference order.
- Pairs: Create a list of every possible pair of candidates (e.g., Alice vs Bob). For each pair, count how many voters prefer one over the other. The winner of the pair gets a "margin" (e.g., 7 votes for Alice, 3 for Bob → Alice wins).
- Sort: Sort all pairs from strongest margin to weakest.
- Lock (the hard part): Go through the sorted pairs. Lock each pair unless it would create a cycle in the graph.
- Winner: The source of the graph (the candidate with no incoming locked edges) is the winner.
Your job is to write the functions for steps 2, 3, 4, and 5. But step 4—lock_pairs—is where most people get stuck.
Step 3: The add_pairs Function
We need to populate the global pairs array. A pair exists if preferences[i][j] > preferences[j][i]. If equal (tie), skip. Algorithmic Implementation of the Tideman Voting System A
Remember: The problem requires that each pair appears only once, with the winner first.
void add_pairs(void)
pair_count = 0;
for (int i = 0; i < candidate_count; i++)
for (int j = i + 1; j < candidate_count; j++)
if (preferences[i][j] > preferences[j][i])
pairs[pair_count].winner = i;
pairs[pair_count].loser = j;
pair_count++;
else if (preferences[j][i] > preferences[i][j])
pairs[pair_count].winner = j;
pairs[pair_count].loser = i;
pair_count++;
// ties are ignored
return;
4.1 Sorting Complexity
A common mistake students make is sorting based only on the raw number of votes for the winner, rather than the margin of victory. However, the Tideman specification dictates sorting by victory strength (margin), which requires accessing both preferences[winner][loser] and preferences[loser][winner].
