So, we are given a 100 long array, with 97 0s and 3 1s of which we do not know the locations. We must find them using only a compare function, which I managed to write (in Python):
def compare(i, j):
comparisons.append((i, j))
if data[i] == data[j]:
return 0
else:
return 1 if data[i] > data[j] else -1
Using this function, we must find all three 1s with using at most 73 comparisons. We must output the compared pairs as a tuple as well as the coordinates of the three 1s.
Now, I tried writing a code with the following logic:
And I thought that maybe because two 1s will use 2 instead of 3 comparisons, it might come down do 73. This was not only long to code (I am studying mathematics, not CS), but I wrote to my prof, and he said this wouldn't work, and that I should try dynamic programming. I'm a bit lost, as I've never solved a coding program that is this limiting, so I have an other idea, which is to do a first parse of the array, going in pairs, so comparing (data[0], data1),(data[2], data[3]),.... This way, no matter how the 1s are placed, I ought to find at least one of them. I would also store all of the results of these comparisons, and then cross-check them with a set of new comparisons, namely (data1,data[2]),(data[5],data[6]),...
Any help is appreciated, specific code would be most useful, so I can understand how such a method would work.
Edit: I almost have it now thanks to @orlp, but I don't see why I still get 75 comparisons:
comparisons = []
def compare(i, j):
comparisons.append((i, j))
if data[i] == data[j]:
return 0
else:
return 1 if data[i] > data[j] else -1
def find_ones(data):
found_ones = []
for i in range(0, len(data), 2):
if compare(i, i + 1) != 0:
found_ones.append(i if data[i] == 1 else i + 1)
if len(found_ones) == 3:
return comparisons, found_ones[0], found_ones[1], found_ones[2]
remaining_pairs = [i for i in range(0, len(data), 2) if i not in found_ones]
for i in range(0, len(remaining_pairs) - 1, 2):
if compare(remaining_pairs[i], remaining_pairs[i + 1]) != 0:
found_ones.extend([remaining_pairs[i], remaining_pairs[i + 1]])
break
if len(found_ones) == 1:
found_ones.extend(remaining_pairs[-2:])
return comparisons, found_ones[0], found_ones[1], found_ones[2]
def get_input_data():
position_1 = int(input("Enter position of first '1' (0-99): "))
position_2 = int(input("Enter position of second '1' (0-99): "))
position_3 = int(input("Enter position of third '1' (0-99): "))
data = [0] * 100
data[position_1] = data[position_2] = data[position_3] = 1
return data
data = get_input_data()
comparisons, a, b, c = find_ones(data.copy())
print("Comparisons:")
for pair in comparisons:
print(pair)
print("\nPositions of '1's:")
print(a, b, c)
print("\nNumber of comparisons:", len(comparisons))
I included the optimizations at the end, didn't I? Don't do the last comparison, if only one 1 has been found the first time around, and the second time don't do the last comparison, because by then we know them to be 1s.
Edit 2: I fixed, some of the issues in the first half, but I just do not see why it isn't down to 73 steps. Also now, it is returning false values. What am I doing wrong?
comparisons = []
def compare(i, j):
comparisons.append((i, j))
if data[i] == data[j]:
return 0
else:
return 1 if data[i] > data[j] else -1
def find_ones(data):
found_ones = []
# Step 1: Initial pairing and comparisons
for i in range(0, len(data)-2, 2):
if compare(i, i + 1) != 0: # One of them is a '1'
found_ones.append(i if data[i] == 1 else i + 1)
if len(found_ones) == 3: # Found all three '1's
return comparisons, found_ones[0], found_ones[1], found_ones[2]
# Check if we need to compare the final pair
if len(found_ones) == 2:
result = compare(len(data) - 2, len(data) - 1)
if result == 1: # '1' is at index len(data) - 2
found_ones.append(len(data) - 2)
elif result == -1: # '1' is at index len(data) - 1
found_ones.append(len(data) - 1)
if len(found_ones) == 3: # Found all three '1's
return comparisons, found_ones[0], found_ones[1], found_ones[2]
# Step 2: Find the pair with the remaining two '1's
remaining_pairs = [i for i in range(0, len(data), 2) if i not in found_ones]
for i in range(0, len(remaining_pairs) - 1, 2):
if compare(remaining_pairs[i], remaining_pairs[i + 1]) != 0: # Found the (1, 1) pair
found_ones.extend([remaining_pairs[i], remaining_pairs[i + 1]])
break
# Step 3: If necessary, deduce the last pair
if len(found_ones) == 1:
found_ones.extend(remaining_pairs[-2:]) # The remaining pair must be (1, 1)
return comparisons, found_ones[0], found_ones[1], found_ones[2]
# Example usage
def get_input_data():
# Replace this with your preferred input method (e.g., user input)
position_1 = int(input("Enter position of first '1' (0-99): "))
position_2 = int(input("Enter position of second '1' (0-99): "))
position_3 = int(input("Enter position of third '1' (0-99): "))
data = [0] * 100
data[position_1] = data[position_2] = data[position_3] = 1
return data
data = get_input_data()
comparisons, a, b, c = find_ones(data.copy()) # Use copy to avoid modifying original
print("Comparisons:")
for pair in comparisons:
print(pair)
print("\nPositions of '1's:")
print(a, b, c)
print("\nNumber of comparisons:", len(comparisons))
Edit 3:
comparisons = []
def compare(i, j):
comparisons.append((i, j))
if data[i] == data[j]:
return 0
else:
return 1 if data[i] > data[j] else -1
def find_ones(data):
found_ones = []
excluded_indices = set() # Track indices already found
# Step 1: Initial pairing and comparisons
for i in range(0, len(data) - 2, 2):
result = compare(i, i + 1)
if result == 1:
found_ones.append(i)
excluded_indices.update({i, i + 1}) # Update excluded indices
elif result == -1:
found_ones.append(i + 1)
excluded_indices.update({i, i - 1}) # Update excluded indices
if len(found_ones) == 3:
return comparisons, found_ones[0], found_ones[1], found_ones[2]
# Check if we need to compare the final pair
if len(found_ones) == 2 and (len(data) - 2) not in excluded_indices and (len(data) - 1) not in excluded_indices:
result = compare(len(data) - 2, len(data) - 1)
if result == 1:
found_ones.append(len(data) - 2)
excluded_indices.update({len(data) - 2, len(data) - 1}) # Update excluded indices
elif result == -1:
found_ones.append(len(data) - 1)
excluded_indices.update({len(data) - 2, len(data) - 1}) # Update excluded indices
if len(found_ones) == 3:
return comparisons, found_ones[0], found_ones[1], found_ones[2]
# Step 2: Find the pair with the remaining two '1's
remaining_pairs = [i for i in range(0, len(data), 2) if i not in excluded_indices]
for i in range(0, len(remaining_pairs) - 1, 2):
if compare(remaining_pairs[i], remaining_pairs[i + 1]) != 0:
found_ones.extend([remaining_pairs[i], remaining_pairs[i + 1]])
break
# Step 3: If necessary, deduce the last pair
if len(found_ones) == 1:
found_ones.extend(remaining_pairs[-2:])
return comparisons, found_ones[0], found_ones[1], found_ones[2]
# Example usage
def get_input_data():
position_1 = int(input("Enter position of first '1' (0-99): "))
position_2 = int(input("Enter position of second '1' (0-99): "))
position_3 = int(input("Enter position of third '1' (0-99): "))
data = [0] * 100
data[position_1] = data[position_2] = data[position_3] = 1
return data
data = get_input_data()
comparisons, a, b, c = find_ones(data)
print("Comparisons:")
for pair in comparisons:
print(pair)
print("\nPositions of '1's:")
print(a, b, c)
print("\nNumber of comparisons:", len(comparisons))
Edit 4: Okay, I believe I fixed the wrong excluding of the indexes, I now see how in both cases it must be i and i + 1. I still don't see how the logic in step 3 is wrong, but I did try to fix it in step 2. If we are in step 2 we still have an even number of elements, all of which hae previously been compared in pairs. Let's say we are here: (0,0)(1,1), where the parentheses mark the compared pairs from the first parse. The i-th element is the first zero of a pair (or the first 1 of a pair), so we compare it with the element that is 2 away from it, meaning the first element of the other pair. In this case we get remaining_pairs(i)<remaining_pairs(i+2), so we add i+2 and i+3 as being 1s. If it was the other way around, then we add i and i+1. It is still slightly off though, what is wrong?
comparisons = []
def compare(i, j):
comparisons.append((i, j))
if data[i] == data[j]:
return 0
else:
return 1 if data[i] > data[j] else -1
def find_ones(data):
found_ones = []
excluded_indices = set() # Track indices already found
# Step 1: Initial pairing and comparisons
for i in range(0, len(data) - 2, 2):
result = compare(i, i + 1)
if result == 1:
found_ones.append(i)
excluded_indices.update({i, i + 1}) # Update excluded indices
elif result == -1:
found_ones.append(i + 1)
excluded_indices.update({i, i + 1}) # Update excluded indices
if len(found_ones) == 3:
return comparisons, found_ones[0], found_ones[1], found_ones[2]
# Check if we need to compare the final pair
if len(found_ones) == 2 and (len(data) - 2) not in excluded_indices and (len(data) - 1) not in excluded_indices:
result = compare(len(data) - 2, len(data) - 1)
if result == 1:
found_ones.append(len(data) - 2)
excluded_indices.update({len(data) - 2, len(data) - 1}) # Update excluded indices
elif result == -1:
found_ones.append(len(data) - 1)
excluded_indices.update({len(data) - 2, len(data) - 1}) # Update excluded indices
if len(found_ones) == 3:
return comparisons, found_ones[0], found_ones[1], found_ones[2]
# Step 2: Find the pair with the remaining two '1's
remaining_pairs = [i for i in range(0, len(data), 2) if i not in excluded_indices]
for i in range(0, len(remaining_pairs) - 1, 2):
result=compare(remaining_pairs[i], remaining_pairs[i + 2])
if result == 1:
found_ones.extend([remaining_pairs[i], remaining_pairs[i + 1]])
break
elif result == -1:
found_ones.extend([remaining_pairs[i+2], remaining_pairs[i + 3]])
break
# Step 3: If necessary, deduce the last pair
if len(found_ones) == 1:
found_ones.extend(remaining_pairs[-2:])
return comparisons, found_ones[0], found_ones[1], found_ones[2]
def get_input_data():
position_1 = int(input("Enter position of first '1' (0-99): "))
position_2 = int(input("Enter position of second '1' (0-99): "))
position_3 = int(input("Enter position of third '1' (0-99): "))
data = [0] * 100
data[position_1] = data[position_2] = data[position_3] = 1
return data
data = get_input_data()
comparisons, a, b, c = find_ones(data)
print("Comparisons:")
for pair in comparisons:
print(pair)
print("\nPositions of '1's:")
print(a, b, c)
print("\nNumber of comparisons:", len(comparisons))
Edit 5: Do I have it?
comparisons = []
def compare(i, j):
comparisons.append((i, j))
if data[i] == data[j]:
return 0
else:
return 1 if data[i] > data[j] else -1
def find_ones(data):
found_ones = []
excluded_indices = set() # Track indices already found
# Step 1: Initial pairing and comparisons
for i in range(0, len(data) - 2, 2):
result = compare(i, i + 1)
if result == 1:
found_ones.append(i)
excluded_indices.update({i, i + 1}) # Update excluded indices
elif result == -1:
found_ones.append(i + 1)
excluded_indices.update({i, i + 1}) # Update excluded indices
if len(found_ones) == 3:
return comparisons, found_ones[0], found_ones[1], found_ones[2]
# Check if we need to compare the final pair
if len(found_ones) == 2 and (len(data) - 2) not in excluded_indices and (len(data) - 1) not in excluded_indices:
result = compare(len(data) - 2, len(data) - 1)
if result == 1:
found_ones.append(len(data) - 2)
excluded_indices.update({len(data) - 2, len(data) - 1}) # Update excluded indices
elif result == -1:
found_ones.append(len(data) - 1)
excluded_indices.update({len(data) - 2, len(data) - 1}) # Update excluded indices
if len(found_ones) == 3:
return comparisons, found_ones[0], found_ones[1], found_ones[2]
# Step 2: Find the pair with the remaining two '1's
remaining_pairs = [i for i in range(0, len(data)) if i not in excluded_indices]
for i in range(0, len(remaining_pairs) - 2, 4):
result=compare(remaining_pairs[i], remaining_pairs[i + 2])
if result == 1:
found_ones.extend([remaining_pairs[i], remaining_pairs[i + 1]])
break
elif result == -1:
found_ones.extend([remaining_pairs[i+2], remaining_pairs[i + 3]])
break
# Step 3: If necessary, deduce the last pair
if len(found_ones) == 1:
found_ones.extend(remaining_pairs[-2:])
return comparisons, found_ones[0], found_ones[1], found_ones[2]
def get_input_data():
position_1 = int(input("Enter position of first '1' (0-99): "))
position_2 = int(input("Enter position of second '1' (0-99): "))
position_3 = int(input("Enter position of third '1' (0-99): "))
data = [0] * 100
data[position_1] = data[position_2] = data[position_3] = 1
return data
data = get_input_data()
comparisons, a, b, c = find_ones(data)
print("Comparisons:")
for pair in comparisons:
print(pair)
print("\nPositions of '1's:")
print(a, b, c)
print("\nNumber of comparisons:", len(comparisons))
```
pcmpeqb
/pmovmskb
), then loop over the set bits if any and usetzcnt
to find their positions. (mask &= mask-1
to clear the lowest set bit, x86blsr
). So this is a fun exercise but not practically relevant for this specific problem. $\endgroup$