cs50 pset3 lockin function - c

i did this implementation of lockin function and it seems to work perfectly in every case i could come up with but when i submit it cs50 says:
":( 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"
thats my code
// Lock pairs into the candidate graph in order, without creating cycles
void lock_pairs(void)
{
// initialising an array with all the untargted candidates (no arrows pointing to them)
bool untargeted[candidate_count];
// initialising a variable to keep track of how many sources (untargted candidates)
int untar = 0;
// chacking all as untargeted
for (int i = 0; i < candidate_count; i++)
{
untargeted[i] = true;
untar++;
}
// iterating over all pairs
for (int i = 0; i < pair_count; i++)
{
// checking if the loser is the only untargeted candidate to prevent cycles
if (!(untargeted[pairs[i].loser] && untar == 1))
{
locked[pairs[i].winner][pairs[i].loser] = true;
// checking if loser was untargted to mark them as a targeted
if (untargeted[pairs[i].loser])
{
untar--;
untargeted[pairs[i].loser] = false;
}
}
}
return;
}
i already submitted and fine with losing the 2 marks i just need to know whats wrong with my code

Related

CS50 - PSET 3 - Tideman - lock_pairs() works when I test it, but fails unit testing

I am at my wits end. I have done my own unit testng and I am getting good results. So, I don't know why check50 is returning errors.
Tideman problem description:
https://cs50.harvard.edu/x/2022/psets/3/tideman/
CS50 IDE:
https://ide.cs50.io
The lock_pairs method:
The function should create the locked graph, adding all edges in decreasing order of victory strength so long as the edge would not create a cycle.
Here is the error
:( lock_pairs locks all pairs when no cycles
lock_pairs did not lock all pairs
:) lock_pairs skips final pair if it creates cycle
:( lock_pairs skips middle pair if it creates a cycle
lock_pairs did not correctly lock all non-cyclical pairs
I am hesitant to look up other similar questions because of the CS50 'honor code' on plagiarism. So, please indulge me this oft-repeated question.
Here is the method:
void lock_pairs(void)
{
// count forward
for (int i = 0; i < pair_count; i++)
{
int winner = pairs[i].winner;
int loser = pairs[i].loser;
if (check_cycle_winner(winner, loser, i) && check_cycle_loser(loser, winner, i))
{
locked[winner][loser] = false;
}
else
{
locked[winner][loser] = true;
}
}
return;
}
Here are the 'helper' functions:
bool check_cycle_winner(int winner, int loser, int index)
{
if (winner == loser) return true;
if (index == 0) return false;
return check_cycle_winner(winner, pairs[index - 1].loser, index -1);
}
bool check_cycle_loser(int loser, int winner, int index)
{
if (loser == winner) return true;
if (index == 0) return false;
return check_cycle_loser(loser, pairs[index - 1].winner, index -1);
}
Full program (to test in CS50 IDE):
https://replit.com/#A1cmae0n/PSET3-Tideman#main.c
Testing lock_pairs in replit:
https://replit.com/#A1cmae0n/CS50-PSET3-Tideman-lockpairs#main.c
Any input would be appreciated. Please indulge me the request to respond Socratically to my question rather than spoil the answer :)
Your code is mistaken because you are looking for full cycles, not for chains, and you should be looking for the latter.
If it helps here I explain the logic of lock pairs
a) You want to lock pair 4 but...
b) pairs[4].loser returns 0, meaning the loser is id 0
c) id 0 won at locked[0][2]
d) id 2 won at locked[2][4]
e) Thus if you lock locked[5][0] as true you create a chain, so you
shouldn't

CS50 Tideman: lock_pairs skips final pair if it creates cycle

After many failed attempts, I managed to used a recursive function to check the locked pairs.
When I check the results, both with the program and manually, I get the correct locked pairs. But I keep getting the "lock_pairs skips final pair if it creates cycle" error, while all other checks run ok.
I don't know how to see what's wrong here. Can you give me a hand?
I'm not asking for someone to tell me how to do it properly, but to point out where is my error, so I can think of the best way to work this out.
Here is my code:
bool find_connections(int i, int j);
int lock_done = 100;
void lock_pairs(void)
{
// Iterates through all the pairs
for (int i = 0; i < pair_count; i++)
{
// lock_done is used in the recursive function as indicator that the locked value is false, and every further process of the loop is unnecessary.
lock_done = 100;
// Calls find_connection function, and sends the index of the pair twice, one for checking the cycle (it remains constant) and one to be replaced by the losing candidate of the found pair.
int is_locked = find_connections(i, i);
locked[pairs[i].winner][pairs[i].loser] = is_locked;
}
return;
}
bool find_connections(int i, int j)
{
// Iterates through all pairs to check for a coincidence between loser of j and winner of r
for (int r = 0; r < pair_count; r++)
{
// If it was confirmed as false, it returns "false"
if (lock_done != 100)
return lock_done;
// Checks coincidence between loser of j and winner of r
if (pairs[j].loser == pairs[r].winner)
{
// When there's a match, if pair is locked and the loser connects to the original winner, then the lock condition is false.
if (pairs[i].winner == pairs[r].loser && locked[pairs[r].winner][pairs[r].loser] == 1)
{
lock_done = 0;
return 0;
}
// Otherwise, it calls the function again to check the connections starting with the new pair.
else if(locked[pairs[r].winner][pairs[r].loser] == 1)
find_connections(i, r);
}
}
// When all pairs are checked, if one was already found as false, then it returns false.
if (lock_done == 0)
return 0;
// Otherwise, there is no cycle, and the locked condition is true.
else
{
lock_done = 1;
return 1;
}
}

CS50 Tideman, the last unsolved check - lock_pairs skips final pair if it creates cycle

I'm working on the CS50x's Tideman problem
(https://cs50.harvard.edu/x/2022/psets/3/tideman/).
All the tests passed except one:
:( lock_pairs skips final pair if it creates cycle
lock_pairs did not correctly lock all non-cyclical pairs
I guess the problem is in my custom function has_circle that checks if there will be a circle in a graph if an edge is placed.
I would really be grateful for your help. I wrote the rest of the code fairly quickly (for a begginer) but this bug is just....
This is the code:
bool has_circle(int loser, int winner)
{
// base case, break
if (winner == loser)
{
return true;
}
// iterate through all pairs to see if our loser is a winner against someone
for (int i = 0; i < pair_count; i++)
{
if (locked[loser][i] == true)
{
// check if primary winner is a loser against i, if edge can be placed
return has_circle(i, winner);
}
}
return false;
}
// Lock pairs into the candidate graph in order, without creating cycles
void lock_pairs(void)
{
//
for (int i = 0; i < pair_count; i++)
{
// check for circle
if (!has_circle(pairs[i].loser, pairs[i].winner))
{
locked[pairs[i].winner][pairs[i].loser] = true;
}
}
return;
}
This line
return has_circle(i, winner);
always returns a value, ending the the loop and the recursion, the first time locked[loser][i] is true, regardless of the actual result of has_circle.
Instead, you want the loop to be able to continue if has_circle returns false, but break the loop and return true when has_circle returns true.
bool has_circle(int loser, int winner)
{
// base case, break
if (winner == loser)
{
return true;
}
// iterate through all pairs to see if our loser is a winner against someone
for (int i = 0; i < pair_count; i++)
{
if (locked[loser][i] && has_circle(i, winner))
{
return true;
}
}
return false;
}

CS50's Tideman: lock_pairs fails to skip the final pair if it creates a cycle (supposedly)

I'm stuck at the lock_pairs function of Tideman. I already wrote the code for it and it looks good. It also behaves as it should when running it through the debugger; however, every time I try it with check50 it gives me an error on "lock pair skips final pair if it creates a cycle".
In order to try it out, I've used examples where the final pair is the one which should be skipped and everything goes as planned when I watch the whole process step by step on the debugger, so I really don't know what I'm missing here.
Here's the explanation of the problem: https://cs50.harvard.edu/x/2022/psets/3/tideman/
void lock_pairs(void)
{
// TODO
// When no_cycle is 0, it indicates that there is no cycle and that locking the pair is safe
int no_cycle = 0;
for (int i = 0; i < pair_count; i++)
{
for (int j = 0; j < pair_count; j++)
{
// We check each pair, looking for a locked pair where the loser of the pair we're checking is the winner.
if (!locked[pairs[i].loser][pairs[j].loser])
{
no_cycle = 0;
continue;
}
else
{
// If the result is true, we check for a possible cycle using the cycle_check function
if (cycle_check(i, j) == false)
{
// If the result is false, we lock the pair and move on
no_cycle = 0;
break;
}
else
{
// If the result is true (indicating a cycle), we change the value of no_cycle to avoid locking the pair
no_cycle = 1;
break;
}
}
}
if (no_cycle == 0)
{
locked[pairs[i].winner][pairs[i].loser] = true;
}
else continue;
}
return;
}
bool cycle_check(i, j)
{
// We check if the loser of the locked pair is the same as our pair's winner or starting point (the end of the chain is also the begining)
if (pairs[j].loser == pairs[i].winner)
{
return true;
}
else
{
//If it isn't, we go through each locked pair, following the chain which could lead to the cycle
for (int h = 0; h < pair_count; h++)
{
if (locked[pairs[j].loser][pairs[h].loser])
{
// Once we find the next link in the chain, we start over
j = h;
if (cycle_check(i, j) == true)
{
// Once we find that there is indeed a cycle, we break recursion
return true;
}
}
}
// If we follow the chain but don't find a cycle, the function returns false and the pair is locked
return false;
}
}
Been stuck forever on this. Any help would be much appreciated.
Btw, english is not my primary language, so please excuse any grammar errors.

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;
}
}
}

Resources