Tag: tideman problem

  • The Solution to CS50 psets 3 Tideman Problem (2022)

    The Solution to CS50 psets 3 Tideman Problem (2022)

    In this problem set, we have to write a code that runs the Tideman election as shown in below code snippet.

    $ ./tideman Alice Bob Charlie
    Number of voters: 5
    Rank 1: Alice
    Rank 2: Charlie
    Rank 3: Bob
    
    Rank 1: Alice
    Rank 2: Charlie
    Rank 3: Bob
    
    Rank 1: Bob
    Rank 2: Charlie
    Rank 3: Alice
    
    Rank 1: Bob
    Rank 2: Charlie
    Rank 3: Alice
    
    Rank 1: Charlie
    Rank 2: Alice
    Rank 3: Bob
    
    Charlie

    In the previous posts, I gave you the solution to the cs50 psets 3 plurality problem, and cs50 psets 3 runoff problem.

    So the plurality election system and runoff election system have their own advantages and disadvantages. Now, let’s see what is the Tideman election system.

    Tideman Election System

    Tideman method is also known as the Ranked pairs method. This system was developed in 1987 by Nicolaus Tideman. This system selects a single winner using votes that express preferences. This method can also be used to create a sorted list of winners.

    So, let’s get back to the problem set, an initial code is given to us.

    Solution

    1. The vote function

    // Update ranks given a new vote
    bool vote(int rank, string name, int ranks[])
    {
        // TODO
        for (int i = 0; i < candidate_count; i++)
        {
            if (strcmp(name, candidates[i]) == 0)
            {
                ranks[rank] = i;
                return true;
            }
        }
        return false;
    }

    2. The record_preferences function

    // Update preferences given one voter's ranks
    void record_preferences(int ranks[])
    {
        // TODO
        for (int i = 0; i < candidate_count; i++)
        {
            for (int j = i + 1; j < candidate_count; j++)
            {
                preferences[ranks[i]][ranks[j]]++;
            }
        }
        return;
    }

    3. The add_pairs function

    // 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 = 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[i][j] < preferences[j][i])
                {
                    pairs[pair_count].winner = j;
                    pairs[pair_count].loser = i;
                    pair_count++;
                }
            }
        }
        return;
    }

    4. The sort_pairs function

    // Sort pairs in decreasing order by strength of victory
    void sort_pairs(void)
    {
        // TODO
        for (int i = 0; i < pair_count; i++)
        {
            int max = i;
            for (int j = i; j < pair_count; j++)
            {
                if (preferences[pairs[j].winner][pairs[j].loser] > preferences[pairs[max].winner][pairs[max].loser])
                {
                    max = j;
                }
            }
            pair temp = pairs[i];
            pairs[i] = pairs[max];
            pairs[max] = temp;
        }
        return;
    }

    5. The cycle function

    // Check for cycle by checking arrow coming into each candidate
    bool cycle(int cycle_end, int cycle_start)
    {
        // Return true if there is a cycle
        if (cycle_end == cycle_start)
        {
            return true;
        }
    
        // Loop through all the candidates
        for (int i = 0; i < candidate_count; i++)
        {
            if (locked[cycle_end][i])
            {
                if (cycle(i, cycle_start))
                {
                    return true;
                }
            }
        }
        return false;
    }

    6. The lock_pairs function

    // Lock pairs into the candidate graph in order, without creating cycles
    void lock_pairs(void)
    {
        // TODO
        for (int i = 0; i < pair_count; i++)
        {
            if (!cycle(pairs[i].loser, pairs[i].winner))
            {
                locked[pairs[i].winner][pairs[i].loser] = true;
            }
        }
        return;
    }

    7. The print_winner function

    // Print the winner of the election
    void print_winner(void)
    {
        // TODO
        for (int i = 0; i < candidate_count; i++)
        {
            bool loser = false;
            for (int j = 0; j < candidate_count; j++)
            {
                if (locked[j][i])
                {
                    loser = true;
                    break;
                }
            }
            if (loser)
            {
                continue;
            }
            if (!loser)
            {
                printf("%s\n", candidates[i]);
            }
        }
        return;
    }

    Full Code

    here is the full code that includes all the functions,

    #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);
    bool cycle(int cycle_end, int cycle_start);
    
    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);
    
                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
    bool vote(int rank, string name, int ranks[])
    {
        // TODO
        for (int i = 0; i < candidate_count; i++)
        {
            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
        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 = 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[i][j] < preferences[j][i])
                {
                    pairs[pair_count].winner = j;
                    pairs[pair_count].loser = i;
                    pair_count++;
                }
            }
        }
        return;
    }
    
    // Sort pairs in decreasing order by strength of victory
    void sort_pairs(void)
    {
        // TODO
        for (int i = 0; i < pair_count; i++)
        {
            int max = i;
            for (int j = i; j < pair_count; j++)
            {
                if (preferences[pairs[j].winner][pairs[j].loser] > preferences[pairs[max].winner][pairs[max].loser])
                {
                    max = j;
                }
            }
            pair temp = pairs[i];
            pairs[i] = pairs[max];
            pairs[max] = temp;
        }
        return;
    }
    
    // Check for cycle by checking arrow coming into each candidate
    
    bool cycle(int cycle_end, int cycle_start)
    {
        // Return true if there is a cycle
        if (cycle_end == cycle_start)
        {
            return true;
        }
    
        // Loop through all the candidates
        for (int i = 0; i < candidate_count; i++)
        {
            if (locked[cycle_end][i])
            {
                if (cycle(i, cycle_start))
                {
                    return true;
                }
            }
        }
        return false;
    }
    
    // Lock pairs into the candidate graph in order, without creating cycles
    void lock_pairs(void)
    {
        // TODO
        for (int i = 0; i < pair_count; i++)
        {
            if (!cycle(pairs[i].loser, pairs[i].winner))
            {
                locked[pairs[i].winner][pairs[i].loser] = true;
            }
        }
        return;
    }
    
    // Print the winner of the election
    void print_winner(void)
    {
        // TODO
        for (int i = 0; i < candidate_count; i++)
        {
            bool loser = false;
            for (int j = 0; j < candidate_count; j++)
            {
                if (locked[j][i])
                {
                    loser = true;
                    break;
                }
            }
            if (loser)
            {
                continue;
            }
            if (!loser)
            {
                printf("%s\n", candidates[i]);
            }
        }
        return;
    }

    Hope this helps you, Good luck!