简体   繁体   中英

PSET 3 Tideman CS50 lock_pairs doesn't lock correctly

i am new to this site so i might not ask my question correctly which i am sorry for but i have been struggling with PSET 3 Tideman for quite a while. Currently i am on lock_pairs and i dont know what to do. Would appreciate your help: These are my prompts for check50:

:) lock_pairs locks all pairs when no cycles
:( lock_pairs skips final pair if it creates cycle
    lock_pairs did not correctly lock all non-cyclical pairs
:( lock_pairs skips middle pair if it creates a cycle
    lock_pairs did not correctly lock all non-cyclical pairs

void lock_pairs(void)
{
    int winner;
    int win_count[MAX];
    int temp_win = 0;
    for (int i = 0; i < pair_count; i++)
    {
        locked[ pairs[i].winner ][ pairs[i].loser ] = true;
        win_count[ pairs[i].winner ]++;
        if (win_count [ pairs[i].winner ] > temp_win )
        {
            winner = pairs[i].winner;
        }
    }
    for ( int p = 0; p < pair_count; p++)
    {
        if (win_count[ pairs[p].winner ] == win_count[winner] && pairs[p].winner != winner )
        {
            for (int i = pair_count - 1; i < -1 ; i--)
            {
                locked[ pairs[i].winner ][ pairs[i].loser ] = false;
                win_count [ pairs[i].winner ]--;
                if (pairs[i].winner == winner ) 
                {
                    win_count[winner]--;
                    for (int j = 0; j < pair_count; j++)
                    {
                        if (win_count[ pairs[j].winner ] > win_count[winner])
                        {
                            winner = pairs[j].winner;
                        }
                        if (win_count[ pairs[j].winner] == win_count[winner] && pairs[j].winner != winner)
                        {
                            break;
                        }
                        
                        
                    }
                }
                else 
                {
                    locked[ pairs[i].winner ][ pairs[i].loser ] = true;
                }
            }
        }
    }
    return;
}

You may have misunderstood the logic required behind lock_pairs , because your function is overly complicated. This is what you're asked to do-

  • Go through each pair one by one, and lock them if necessary

  • How to know, if it is necessary ? Simple, you make sure locking them does not constitute a circle

  • What does "constitute a circle" mean? This is explained very well by the course itself. More info right there

    But basically,

    How would this work in the case of the votes above? Well, the biggest margin of victory for a pair is Alice beating Bob, since 7 voters prefer Alice over Bob (no other head-to-head matchup has a winner preferred by more than 7 voters). So the Alice-Bob arrow is locked into the graph first. The next biggest margin of victory is Charlie's 6-3 victory over Alice, so that arrow is locked in next.

    Next up is Bob's 5-4 victory over Charlie. But notice: if we were to add an arrow from Bob to Charlie now, we would create a cycle, Since the graph can't allow cycles, we should skip this edge. and not add it to the graph at all, If there were more arrows to consider, we would look to those next, but that was the last arrow. so the graph is complete.

    This step-by-step process is shown below, with the final graph at right.

  • Now the real deal, how do you put this in code?

    Like this-

     // Recursive function to check if entry makes a circle bool makes_circle(int cycle_start, int loser) { if (loser == cycle_start) { // If the current loser is the cycle start // The entry makes a circle return true; } for (int i = 0; i < candidate_count; i++) { if (locked[loser][i]) { if (makes_circle(cycle_start, i)) { // Forward progress through the circle return true; } } } return false; }

    Essentially, to check if locking in a winner->loser makes a circle, you walk back the entries you have locked starting from the loser and going towards all the candidates this loser has won against . If you reach the winner somewhere along the way, that's a circle if I've ever seen one.

    Note that circle_start though, lest it gets confusing. That's only there to remember the original circle start (which is the winner in the main loop in lock_pairs ). This is constant throughout the entire recursion. Remember, once again, our goal is to iterate through all the candidates loser has won against (and also have been locked) and make sure none of these are circle_start (aka the winner that we are about to lock in ).

So, that function right there does all the heavy lifting, your lock_pairs function is gonna be extremely simple-

// Lock pairs into the candidate graph in order, without creating cycles
void lock_pairs()
{
    for (int i = 0; i < pair_count; i++)
    {
        if (!makes_circle(pairs[i].winner, pairs[i].loser))
        {
            // Lock the pair unless it makes a circle
            locked[pairs[i].winner][pairs[i].loser] = true;
        }
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM