Debugging the solution to a possible Bipartition - python

I came across this problem
We want to split a group of n people (labeled from 1 to n)
into two groups of any size. Each person may dislike some other people,
and they should not go into the same group.
Given the integer n and the array dislikes where dislikes[i] = [ai, bi]
indicates that the person labeled ai does not like the person labeled bi,
return true if it is possible to split everyone into two groups in this way.
Example 1:
Input: n = 4, dislikes = [[1,2],[1,3],[2,4]]
Output: true
Explanation: group1 [1,4] and group2 [2,3].
Example 2:
Input: n = 3, dislikes = [[1,2],[1,3],[2,3]]
Output: false
Example 3:
Input: n = 5, dislikes = [[1,2],[2,3],[3,4],[4,5],[1,5]]
Output: false
Below is my approach to the solution:
create two lists, group1 and group2 and initialise group1 with 1
generate all the numbers from 2 to n in a variable called num
check if num is enemy with group1 elements, if yes, then check if num is enemy with group2 elements, if yes as well, return False
else put num in its respective group and goto step 2 with the next value
return True
below is the code implementation
class Solution(object):
def possibleBipartition(self, n, dislikes):
"""
:type n: int
:type dislikes: List[List[int]]
:rtype: bool
"""
group1 = [1]
group2 = []
for num in range(2, n+1):
put_to_group_1 = 1
for _n in group1:
if [_n, num] in dislikes or [num, _n] in dislikes:
put_to_group_1 = 0
break
put_to_group_2 = 1
for _n in group2:
if[_n, num] in dislikes or [num, _n] in dislikes:
put_to_group_2 = 0
break
if put_to_group_1 == 0 and put_to_group_2 == 0:
return False
if put_to_group_1 == 1:
group1.append(num)
else:
group2.append(num)
return True
However for the following input I am getting False, but the expected output isTrue.
50
[[21,47],[4,41],[2,41],[36,42],[32,45],[26,28],[32,44],[5,41],[29,44],[10,46],[1,6],[7,42],[46,49],[17,46],[32,35],[11,48],[37,48],[37,43],[8,41],[16,22],[41,43],[11,27],[22,44],[22,28],[18,37],[5,11],[18,46],[22,48],[1,17],[2,32],[21,37],[7,22],[23,41],[30,39],[6,41],[10,22],[36,41],[22,25],[1,12],[2,11],[45,46],[2,22],[1,38],[47,50],[11,15],[2,37],[1,43],[30,45],[4,32],[28,37],[1,21],[23,37],[5,37],[29,40],[6,42],[3,11],[40,42],[26,49],[41,50],[13,41],[20,47],[15,26],[47,49],[5,30],[4,42],[10,30],[6,29],[20,42],[4,37],[28,42],[1,16],[8,32],[16,29],[31,47],[15,47],[1,5],[7,37],[14,47],[30,48],[1,10],[26,43],[15,46],[42,45],[18,42],[25,42],[38,41],[32,39],[6,30],[29,33],[34,37],[26,38],[3,22],[18,47],[42,48],[22,49],[26,34],[22,36],[29,36],[11,25],[41,44],[6,46],[13,22],[11,16],[10,37],[42,43],[12,32],[1,48],[26,40],[22,50],[17,26],[4,22],[11,14],[26,39],[7,11],[23,26],[1,20],[32,33],[30,33],[1,25],[2,30],[2,46],[26,45],[47,48],[5,29],[3,37],[22,34],[20,22],[9,47],[1,4],[36,46],[30,49],[1,9],[3,26],[25,41],[14,29],[1,35],[23,42],[21,32],[24,46],[3,32],[9,42],[33,37],[7,30],[29,45],[27,30],[1,7],[33,42],[17,47],[12,47],[19,41],[3,42],[24,26],[20,29],[11,23],[22,40],[9,37],[31,32],[23,46],[11,38],[27,29],[17,37],[23,30],[14,42],[28,30],[29,31],[1,8],[1,36],[42,50],[21,41],[11,18],[39,41],[32,34],[6,37],[30,38],[21,46],[16,37],[22,24],[17,32],[23,29],[3,30],[8,30],[41,48],[1,39],[8,47],[30,44],[9,46],[22,45],[7,26],[35,42],[1,27],[17,30],[20,46],[18,29],[3,29],[4,30],[3,46]]
Can anyone tell me where I might be going wrong with the implementation?

Consider a scenario:
Let's assume that in the dislikes array, we have [1,6],[2,6] among other elements (so 6 hates 1 and 2).
Person 1 doesn't hate anybody else
After placing everybody into groups, let's say 2 gets placed in group 2.
While placing 6, you can't put it in either group, since it conflicts with 1 in group 1 and 2 in group 2.
6 could have been placed in group 1 if you didn't start with the assumption of placing 1 in group 1 (ideally 1 could have been placed in group 2 without conflict).
Long story short, don't start with person 1 in group 1. Take the first element in the dislikes array, put either of them in either group, and then continue with the algorithm.

Related

how to find out binary number similarity

Recently I have appeared in a coding challenge where one of the question is as below
There are N cars, each having some of M features. A car feature list is given as binary string.
for ex: 0000111
0 means feature not supported.
Two cars are similar if their feature description differs by atmost one feature. for ex: 11001, 11000 are similar for every car, find count of similar cars in a list of cars with features
I have tried to solve the problem with XOR operator. But it worked for few test cases
cars = ["100", "110", "010", "011", "100"]
Here for car at 0th index is similar to 1st and 4th. so output should be 2. similar for all the index car need to be found out with which it is similar.
Solution I tried:
def solution(cars):
ret_list = []
for i in range(len(cars)):
count = 0
for j in range(len(cars)):
if i != j:
if (int(cars[i]) ^ int(cars[j])) <= 100:
count += 1
ret_list.append(count)
print(ret_list)
return ret_list
output : [2, 3, 2, 1, 2]
But this doesn't fit to when input is like:
cars = ["1000", "0110", "0010", "0101", "1010"]
Can someone please suggest a better solution that works for all kind of binary number
Try this:
def isPowerOf2(x):
return (x & (x - 1)) == 0
def areSimilar(x, y):
return isPowerOf2(x ^ y)
def solution(cars):
similarPairCount = 0
for i in range(len(cars) - 1):
for j in range(i + 1, len(cars)):
if areSimilar(int(cars[i], 2), int(cars[j], 2)):
similarPairCount += 1
return similarPairCount
import numpy as np
# ...
# conversion to int
cars_int = np.array([int(c,2) for c in cars]).reshape(1,-1)
# matrix to compare all against all
compare = (cars_int ^ cars_int.T) # or exclusive
# result of cars with 0 or 1 hamming distance
# (not including comparison of each car with itself)
result = (np.sum(compare & (compare-1) == 0) - cars_int.size) // 2
if you want a list with similarity by car:
# ...
result_per_car = np.sum(compare & (compare-1) == 0, axis=1) - 1

Why does ortools set constraint rigidly?

I went through google ortools scheduling tutorial and created slightly different constraint.
Say, that we have a df, that indicates the following:
Each nurse can work only on the preassigned shift. According to the table, nurse 0 must work either on shift 0 or 1, the nurse 2 must work only on the shift 2 etc.
Furthermore, I added the following constraint: "If nurse_0 takes shift_0, then she must take shif_1". It's shown by column "is_child" - shift_1 is child_shift for shift_0 for nurse_0.
df_dict = {
"slot_number":[1,1,2,2,3],
"asset_name":['0','1','0','1','2'],
"is_child":["No","No","Yes",'No','No']
}
df = pd.DataFrame.from_dict(df_dict)
Create variables and a model:
num_nurses = 3
num_shifts = 3
all_nurses = range(num_nurses)
all_shifts = range(num_shifts)
model = cp_model.CpModel()
shifts = {}
for n in all_nurses:
for s in all_shifts:
shifts[(n, s)] = model.NewBoolVar('shift_n%is%i' % (n, s))
One nurse can take only one shift:
for s in all_shifts:
model.Add(sum(shifts[(n, s)] for n in all_nurses) == 1)
My constraint:
# whether the slot (key) have any children in other slots
children = {0: [1], 1: [] ,2: []}
# what nurses are considered the children (values) in which slot (key)
nurse_child_sched = {0:[], 1:[0], 2:[]}
# In this case if nurse 0 take slot 0, then she must take slot 1 too.
for s in all_shifts:
for n in all_nurses:
if (children[s]):
for child in children[s]:
if n in nurse_child_sched[child]:
model.Add((shifts[(n,s)] + shifts[(n,child)])==2)
print(f"{s}-parent_slot and {child}-child_slot were connected for nurse {n}")
The code to create schedules and show solutions:
class NursesPartialSolutionPrinter(cp_model.CpSolverSolutionCallback):
"""Print intermediate solutions."""
def __init__(self, shifts, num_nurses, num_shifts, sols):
cp_model.CpSolverSolutionCallback.__init__(self)
self._shifts = shifts
self._num_nurses = num_nurses
self._num_shifts = num_shifts
self._solutions = set(sols)
self._solution_count = 0
def on_solution_callback(self):
if self._solution_count in self._solutions:
print('Solution %i' % self._solution_count)
for n in range(self._num_nurses):
is_working = False
for s in range(self._num_shifts):
if self.Value(self._shifts[(n, s)]):
is_working = True
print(' Nurse %i works shift %i' % (n, s))
if not is_working:
print(' Nurse {} does not work'.format(n))
print()
self._solution_count += 1
def solution_count(self):
return self._solution_count
solver = cp_model.CpSolver()
solver.parameters.linearization_level = 0
a_few_solutions = range(5)
solution_printer = NursesPartialSolutionPrinter(shifts, num_nurses, num_shifts,a_few_solutions)
solver.SearchForAllSolutions(model, solution_printer)
And, finally, I have the following result:
Solution 0
Nurse 0 works shift 0
Nurse 0 works shift 1
Nurse 1 works shift 2
Nurse 2 does not work
Solution 1
Nurse 0 works shift 0
Nurse 0 works shift 1
Nurse 1 does not work
Nurse 2 works shift 2
Solution 2
Nurse 0 works shift 0
Nurse 0 works shift 1
Nurse 0 works shift 2
Nurse 1 does not work
Nurse 2 does not work
However, according to my logic, there must be also at least the solution below. I realize, that my constraint says the model to put nurse_0 on shift_0, but I need to just put the relation between two slots in case if nurse_0 is putted on first shift and no constraints otherwise. Thanks in advance.
Solution x
Nurse 1 works shift 0
Nurse 0 works shift 1
Nurse 0 works shift 2
Nurse 1 does not work
Nurse 2 does not work
Side note:
One nurse can take only one shift:
for s in all_shifts:
model.Add(sum(shifts[(n, s)] for n in all_nurses) == 1)
Here you have written "each shift is assigned to exactly one nurse"
If you wan to express "one nurse can take only one shift" you should write:
for n in all_nurses:
model.Add(sum(shifts[(n, s)] for s in all_shifts) == 1)
note: but in this case since nurse exactly work one shift, child shift is impossible so I guess your code is OK and not the comment...

PYTHON - "Love for Mathematics"

I just finished a challenge on Dcoder ("Love for Mathematics") using Python. I failed two test-cases, but got one right. I used somewhat of a lower level of Python for the same as I haven't explored more yet, so I'm sorry if it looks a bit too basic.The Challenge reads:
Students of Dcoder school love Mathematics. They love to read a variety of Mathematics books. To make sure they remain happy, their Mathematics teacher decided to get more books for them.
A student would become happy if there are at least X Mathematics books in the class and not more than Y books because they know "All work and no play makes Jack a dull boy".The teacher wants to buy a minimum number of books to make the maximum number of students happy.
The Input
The first line of input contains an integer N indicating the number of students in the class. This is followed up by N lines where every line contains two integers X and Y respectively.
#Sample Input
5
3 6
1 6
7 11
2 15
5 8
The Output
Output two space-separated integers that denote the minimum number of mathematics books required and the maximum number of happy students.
Explanation: The teacher could buy 5 books and keep student 1, 2, 4 and 5 happy.
#Sample Output
5 4
Constraints:
1 <= N <= 10000
1 <= X, Y <= 10^9
My code:
n = int(input())
l = []
mi = []
ma = []
for i in range(n):
x, y = input().split()
mi.append(int(x))
ma.append(int(y))
if i == 0:
h=ma[0]
else:
if ma[i]>h:
h=ma[i]
for i in range(h):
c = 0
for j in range(len(mi)):
if ma[j]>=i and mi[j]<=i:
c+=1
l.append(c)
great = max(l)
for i in range(1,len(l)+1):
if l[i]==great:
print(i,l[i])
break
My Approach:
I first assigned the two minimum and maximum variables to two different lists - one containing the minimum values, and the other, the maximum. Then I created a loop that processes all numbers from 0 to the maximum possible value of the list containing maximum values and increasing the count for each no. by 1 every time it lies within the favorable range of students.
In this specific case, I got that count list to be (for the above given input):
[1,2,3,3,4,4,3,3,2 ...] and so on. So I could finalize that 4 would be the maximum no. of students and that the first index of 4 in the list would be the minimum no. of textbooks required.
But only 1 test-case worked and two failed. I would really appreciate it if anyone could help me out here.
Thank You.
This problem is alike minimum platform problem.
In that, you need to sort the min and max maths books array in ascending order respectively. Try to understand the problem from the above link (platform problem) then this will be a piece of cake.
Here is your solution:
n = int(input())
min_books = []
max_books = []
for i in range(n):
x, y = input().split()
min_books.append(int(x))
max_books.append(int(y))
min_books.sort()
max_books.sort()
happy_st_result = 1
happy_st = 1
books_needed = min_books[0]
i = 1
j = 0
while (i < n and j < n):
if (min_books[i] <= max_books[j]):
happy_st+= 1
i+= 1
elif (min_books[i] > max_books[j]):
happy_st-= 1
j+= 1
if happy_st > happy_st_result:
happy_st_result = happy_st
books_needed = min_books[i-1]
print(books_needed, happy_st_result)
Try this, and let me know if you need any clarification.
#Vinay Gupta's logic and explanation is correct. If you think on those lines, the answer should become immediately clear to you.
I have implemented the same logic in my code below, except using fewer lines and cool in-built python functions.
# python 3.7.1
import itertools
d = {}
for _ in range(int(input())):
x, y = map(int, input().strip().split())
d.setdefault(x, [0, 0])[0] += 1
d.setdefault(y, [0, 0])[1] += 1
a = list(sorted(d.items(), key=lambda x: x[0]))
vals = list(itertools.accumulate(list(map(lambda x: x[1][0] - x[1][1], a))))
print(a[vals.index(max(vals))][0], max(vals))
The above answer got accepted in Dcoder too.

How to get the correct number of distinct combination locks with a margin or error of +-2?

I am trying to solve the usaco problem combination lock where you are given a two lock combinations. The locks have a margin of error of +- 2 so if you had a combination lock of 1-3-5, the combination 3-1-7 would still solve it.
You are also given a dial. For example, the dial starts at 1 and ends at the given number. So if the dial was 50, it would start at 1 and end at 50. Since the beginning of the dial is adjacent to the end of the dial, the combination 49-1-3 would also solve the combination lock of 1-3-5.
In this program, you have to output the number of distinct solutions to the two lock combinations. For the record, the combination 3-2-1 and 1-2-3 are considered distinct, but the combination 2-2-2 and 2-2-2 is not.
I have tried creating two functions, one to check whether three numbers match the constraints of the first combination lock and another to check whether three numbers match the constraints of the second combination lock.
a,b,c = 1,2,3
d,e,f = 5,6,7
dial = 50
def check(i,j,k):
i = (i+dial) % dial
j = (j+dial) % dial
k = (k+dial) % dial
if abs(a-i) <= 2 and abs(b-j) <= 2 and abs(c-k) <= 2:
return True
return False
def check1(i,j,k):
i = (i+dial) % dial
j = (j+dial) % dial
k = (k+dial) % dial
if abs(d-i) <= 2 and abs(e-j) <= 2 and abs(f-k) <= 2:
return True
return False
res = []
count = 0
for i in range(1,dial+1):
for j in range(1,dial+1):
for k in range(1,dial+1):
if check(i,j,k):
count += 1
res.append([i,j,k])
if check1(i,j,k):
count += 1
res.append([i,j,k])
print(sorted(res))
print(count)
The dial is 50 and the first combination is 1-2-3 and the second combination is 5-6-7.
The program should output 249 as the count, but it instead outputs 225. I am not really sure why this is happening. I have added the array for display purposes only. Any help would be greatly appreciated!
You're going to a lot of trouble to solve this by brute force.
First of all, your two check routines have identical functionality: just call the same routine for both combinations, giving the correct combination as a second set of parameters.
The critical logic problem is handling the dial wrap-around: you miss picking up the adjacent numbers. Run 49 through your check against a correct value of 1:
# using a=1, i=49
i = (1+50)%50 # i = 1
...
if abs(1-49) <= 2 ... # abs(1-49) is 48. You need it to show up as 2.
Instead, you can check each end of the dial:
a_diff = abs(i-a)
if a_diff <=2 or a_diff >= (dial-2) ...
Another way is to start by making a list of acceptable values:
a_vals = [(a-oops) % dial] for oops in range(-2, 3)]
... but note that you have to change the 0 value to dial. For instance, for a value of 1, you want a list of [49, 50, 1, 2, 3]
With this done, you can check like this:
if i in a_vals and j in b_vals and k in c_vals:
...
If you want to upgrade to the itertools package, you can simply generate all desired combinations:
combo = set(itertools.product(a_list, b_list_c_list) )
Do that for both given combinations and take the union of the two sets. The length of the union is the desired answer.
I see the follow-up isn't obvious -- at least, it's not appearing in the comments.
You have 5*5*5 solutions for each combination; start with 250 as your total.
Compute the sizes of the overlap sets: the numbers in each triple that can serve for each combination. For your given problem, those are [3],[4],[5]
The product of those set sizes is the quantity of overlap: 1*1*1 in this case.
The overlapping solutions got double-counted, so simply subtract the extra from 250, giving the answer of 249.
For example, given 1-2-3 and 49-6-6, you would get sets
{49, 50, 1}
{4}
{4, 5}
The sizes are 3, 1, 2; the product of those numbers is 6, so your answer is 250-6 = 244
Final note: If you're careful with your modular arithmetic, you can directly compute the set sizes without building the sets, making the program very short.
Here is one approach to a semi-brute-force solution:
import itertools
#The following code assumes 0-based combinations,
#represented as tuples of numbers in the range 0 to dial - 1.
#A simple wrapper function can be used to make the
#code apply to 1-based combos.
#The following function finds all combos which open lock with a given combo:
def combos(combo,tol,dial):
valids = []
for p in itertools.product(range(-tol,1+tol),repeat = 3):
valids.append(tuple((x+i)%dial for x,i in zip(combo,p)))
return valids
#The following finds all combos for a given iterable of target combos:
def all_combos(targets,tol,dial):
return set(combo for target in targets for combo in combos(target,tol,dial))
For example, len(all_combos([(0,1,2),(4,5,6)],2,50)) evaluate to 249.
The correct code for what you are trying to do is the following:
dial = 50
a = 1
b = 2
c = 3
d = 5
e = 6
f = 7
def check(i,j,k):
if (abs(a-i) <= 2 or (dial-abs(a-i)) <= 2) and \
(abs(b-j) <= 2 or (dial-abs(b-j)) <= 2) and \
(abs(c-k) <= 2 or (dial-abs(c-k)) <= 2):
return True
return False
def check1(i,j,k):
if (abs(d-i) <= 2 or (dial-abs(d-i)) <= 2) and \
(abs(e-j) <= 2 or (dial-abs(e-j)) <= 2) and \
(abs(f-k) <= 2 or (dial-abs(f-k)) <= 2):
return True
return False
res = []
count = 0
for i in range(1,dial+1):
for j in range(1,dial+1):
for k in range(1,dial+1):
if check(i,j,k):
count += 1
res.append([i,j,k])
elif check1(i,j,k):
count += 1
res.append([i,j,k])
print(sorted(res))
print(count)
And the result is 249, the total combinations are 2*(5**3) = 250, but we have the duplicates: [3, 4, 5]

How to compute the number of edges to change to make the undirected graph a single component?

I was trying to solve this problem with the following code. But the answers aren't accurate for all inputs.
Problem Statement
There are N cities and N one-way bridges in Byteland. There is exactly one incoming and one outgoing
bridge for each city.
Byteland wants to be "elligible" to host the World Cup. A country is "elligible" for the World
Cup, if and only if you can travel from any city to any other city of that country. You are asked to perform
the minimum number of steps to help Byteland become an elligible World Cup host.
For each step you can swap the destinations of two bridges.
For example: We have two bridges A -> B and
C -> D (there is a bridge from A to B and from C to D ). If we swap their destinations, we will have two
bridges A -> D and C -> B .
Input Format
First line contains one integer, T denoting the number of test cases.
For each test there will be two lines:
First line contains one integer, N.
Second line contains N integers, where the X th integer denotes city where bridge goes from city X .
Output Format
Just print the answer to the problem, one line per case.
Sample Input
2
4
3 1 2 4
3
2 3 1
Sample Output
1
0
My Code
for i in range(input()):
n = input()
bridges = {}
connection = [int(y) for y in raw_input().split(' ')]
for j in range(n):
bridges[j+1] = connection[j]
#print bridges
count = 0
swapped = True
for k in range(1, n+1):
if swapped:
swapped = False
for j in range(1, n+1):
if bridges[bridges[j]] == j:
bridges[j], bridges[1 if (j+1)%n == 0 else (j+1)%n] = bridges[1 if (j+1)%n == 0 else (j+1)%n], bridges[j]
swapped = True
#print bridges
count += 1
print count
You have to compute the connected components, then the number of swap is equal to the number of components minus one.
for i in range(int(input())):
N = int(input())
bridges = {index + 1: int(connection) for index, connection in enumerate(input().split())}
visited = set()
component_count = 0
towns = list(bridges.keys())
while towns:
current = towns[0]
component = set()
while current not in visited:
towns.remove(current)
visited.add(current)
current = bridges[current]
component_count += 1
print(component_count - 1)
The code does the following:
start at the first town not visited yet (outer loop), and visit as much town as possible followinng the bridges connections (inner loop)
each time the inner loop breaks, it means that we met a town we already met which makes a component in the graph.
Break the loop and increment the number of component. Start again with a new twon that is not visited
This gives the correct result because we are guaranteed that components are cycles, you can break the cycle (swap a connection) to connect a component to another without breaking the component.

Categories