Path finding: A star not same length from A to B than from B to A - python-3.x

I am implementing the A star algorithm with the Manhattan distance for the 8 puzzle. [ The solution is in spiral form]
1 2 3
8 0 4
7 6 5
In some case, going from A to B will not take the same number of steps as going from B to A.
I think this is because it does not pick the same state on the open list, when they have the same cost, thus, not expanding the same nodes.
From
7 6 4
1 0 8
2 3 5
(A -> B)
7 6 4
1 8 0
2 3 5
(B -> A)
7 6 4
1 3 8
2 0 5
Which both have the same value using Manhattan distance.
Should I explore all path with the same value?
Or should I change the heuristic to have some kind of tie-breaker?
Here is the relevant part of the code
def solve(self):
cost = 0
priority = 0
self.parents[str(self.start)] = (None, 0, 0)
open = p.pr() #priority queue
open.add(0, self.start, cost)
while open:
current = open.get()
if current == self.goal:
return self.print_solution(current)
parent = self.parents[str(current)]
cost = self.parents[str(current)][2] + 1
for new_state in self.get_next_states(current):
if str(new_state[0]) not in self.parents or cost < self.parents[str(new_state[0])][2]:
priority = self.f(new_state) + cost
open.add(priority, new_state[0], cost)
self.parents[str(new_state[0])] = (current, priority, cost)

After wasting so much time re-writing my "solve" function many different ways, for nothing,
I finally found the problem.
def get_next_states(self, mtx, direction):
n = self.n
pos = mtx.index(0)
if direction != 1 and pos < self.length and (pos + 1) % n:
yield (self.swap(pos, pos + 1, mtx),pos, 3)
if direction != 2 and pos < self.length - self.n:
yield (self.swap(pos, pos + n, mtx),pos, 4)
if direction != 3 and pos > 0 and pos % n:
yield (self.swap(pos, pos - 1, mtx),pos, 1)
if direction != 4 and pos > n - 1:
yield (self.swap(pos, pos - n, mtx),pos, 2)
It was in this function. The last if used to be "if 4 and pos > n:"
So there were unexplored states..
2 days for a "-1"
It will teach me to do more unit testing

Related

Python(AI Constraint satisfaction problem) Fitting square and/or rectangular (2d) tiles onto a rectangular ground

I have to arrange and/or fit 2d tiles into a 2d square or rectangular plane with AI algorithm using python program. Each tile has a length and width. For example if a plane is 4x3 and set of tiles is
S={(2,3),(1,2),(2,2)}
these tiles can be rotated 90 degrees in order to fit the matrix.
input
first line contains length and width of the plane
second line number of tiles
and then the length,width of the subsequent tiles
but the inputs should be tab seperated
for eg
4 3
3
2 3
1 2
2 2
output
for eg
1 1 2 2
1 1 3 3
1 1 3 3
I have trouble solving this as i have to use only standard libraries in python no NumPy and no CSP library
~Edit 2`
my code so far I cant figure out how to add algorithm without csp library or to generate grid
from sys import stdin
a = stdin.readline()
x = a.split()
rectangular_plane = [[0] * int(x[0]) for i in range(int(x[1]))]
num_of_rectangles = stdin.readline()
r_widths = []
r_lengths= []
for l in range(int(num_of_rectangles)):
b = stdin.readline()
y = b.split()
r_lengths.insert(l,y[0])
r_widths.insert(l,y[1])
I've solved task with backtracking approach and without any non-standard modules.
Try it online!
import sys
nums = list(map(int, sys.stdin.read().split()))
pw, ph = nums[0:2]
ts = list(zip(nums[3::2], nums[4::2]))
assert len(ts) == nums[2]
if sum([e[0] * e[1] for e in ts]) != pw * ph:
print('Not possible!')
else:
def Solve(*, it = 0, p = None):
if p is None:
p = [[0] * pw for i in range(ph)]
if it >= len(ts):
for e0 in p:
for e1 in e0:
print(e1, end = ' ')
print()
return True
for tw, th in [(ts[it][0], ts[it][1]), (ts[it][1], ts[it][0])]:
zw = [0] * tw
ow = [it + 1] * tw
for i in range(ph - th + 1):
for j in range(pw - tw + 1):
if all(p[k][j : j + tw] == zw for k in range(i, i + th)):
for k in range(i, i + th):
p[k][j : j + tw] = ow
if Solve(it = it + 1, p = p):
return True
for k in range(i, i + th):
p[k][j : j + tw] = zw
return False
if not Solve():
print('Not possible!')
Example input:
4 3
3
2 3
1 2
2 2
Output:
1 1 2 2
1 1 3 3
1 1 3 3

Max Points on a Line with python 3

algorithm question:
Given n points on a 2D plane, find the maximum number of points that lie on the same straight line.
Example 1:
Input: [[1,1],[2,2],[3,3]]
Output: 3
Explanation:
^
|
| o
| o
| o
+------------->
0 1 2 3 4
Example 2:
Input: [[1,1],[3,2],[5,3],[4,1],[2,3],[1,4]]
Output: 4
the working python 3 code is below:
wondering
snippet 1 d[slope] = d.get(slope, 1) + 1 is working
but why this snippet 2 is not working correctly for example 2 even though snippet 1 and 2 are the same
if slope in d:
d[slope] += 1
else:
d[slope] = 1
def gcd(self, a, b):
if b == 0:
return a
return self.gcd(b, a%b)
def get_slope(self, p1, p2):
dx = p1[0] - p2[0]
dy = p1[1] - p2[1]
c = self.gcd(dx, dy)
dx /= c
dy /= c
return str(dy) + "/" + str(dx)
def is_same_points(self, p1:List[int], p2:List[int]):
return p1[0] == p2[0] and p1[1] == p2[1]
def maxPoints(self, points: List[List[int]]) -> int:
if not points:
return 0
n = len(points)
count = 1
for i in range(0, n):
d = {}
duped = 0
localmax = 1
p1 = points[i]
for j in range(i+1, n):
p2 = points[j]
if self.is_same_points(p1, p2):
duped += 1
else:
slope = self.get_slope(p1, p2)
# 1) not work: output is 3 in example 2
# if slope in d:
# d[slope] += 1
# else:
# d[slope] = 1
# 2) works: correct output 4 for example 2
d[slope] = d.get(slope, 1) + 1
localmax = max(localmax, d[slope]);
count = max(count, localmax + duped)
return count
Interesting problem and nice solution.
The reason why the commented out code doesn't work is because of that:
else:
d[slope] = 1 ## correct would be d[slope] = 2
Every 2 points are on the same line, you are counting only one point for the first two p1 p2, thus you get one less in the final answer.

Code fails on Test case. (InterQuartile Range)

This is a challenge from 10 Day statistics on Hackerrank.(https://www.hackerrank.com/challenges/s10-interquartile-range/problem?h_r=next-challenge&h_v=zen)
Task :
Task
The interquartile range of an array is the difference between its first (Q1) and third (Q3) quartiles (i.e., Q3 - Q1).
Given an array,X, of n integers and an array, F, representing the respective frequencies of X's elements, construct a data set, S, where each xi occurs at frequency fi. Then calculate and print S's interquartile range, rounded to a scale of 1 decimal place (i.e., 12.3 format).
Following is my code.
n = int(input())
x = list(map(int, input().split()))
f = list(map(int, input().split()))
s = []
for i in range(len(x)):
j = f[i]
for k in range(j):
s.append(x[i])
n = len(s)
s.sort()
if n%2 == 0:
Q21 = s[n//2]
Q22 = s[n//2 - 1]
Q2 = (Q21 + Q22) / 2
else:
Q2 = s[n//2]
LH = s[:n//2]
if n%2==0:
UH = s[n//2:]
else:
UH = s[n//2+1:]
Q1_len = len(LH)
Q3_len = len(UH)
if Q1_len%2 == 0:
Q11 = LH[Q1_len//2]
Q12 = LH[Q1_len//2 - 1]
Q1 = (Q11 + Q12) / 2
else:
Q1 = LH[Q1_len//2]
if Q3_len%2 == 0:
Q31 = UH[Q3_len//2]
Q32 = UH[Q3_len//2 - 1]
Q3 = (Q31 + Q32) / 2
else:
Q3 = UH[Q3_len//2]
print(round(Q3 - Q1,1))
# print(int(Q2))
# print(int(Q3))
Here is the test case: with std input.
5
10 40 30 50 20
1 2 3 4 5
Expected output:
30.0
My code output:
30.0 # I get this output on my code editor but not on Hackerrank
Can someone help me on this where I am wrong ?
I get the output what is expected but it shows as failed.
print(float(Q3 - Q1))
Basically is the answer.

Implement a function that rounds a number to the nearest number that is divisible by X

I have the following code.
Implement the function nearestX that rounds a number to the nearest number that is divisible by X. For example, if 13 is being rounded to the nearest 5 it rounds to 15. If the number is exactly between two possible numbers, it should be rounded up.
def nearestX(num, x):
if x == 0:
return num
remainder = abs(num % x)
print(remainder)
if remainder == 0:
return num
if num < 0:
return -(abs(num) - remainder)
else:
return num + x - remainder
But it doesn't work for nearest(12,5) for example which should give 10 as this is closer than 15 but it returns 15 instead.
You can convert the given number to a decimal.Decimal object so that you can specify the type of rounding based on whether the number of positive or negative when you convert it back to an integer with the to_integral_exact method:
from decimal import Decimal, ROUND_HALF_UP, ROUND_HALF_DOWN
def nearestX(num, x):
return (Decimal(num) / x).to_integral_exact(
rounding=ROUND_HALF_DOWN if num < 0 else ROUND_HALF_UP) * x
Note that nearestX(num, x) is either x * (num // x) or (x + 1) * (num // x). Accounting for the round up rule, we have:
def nearestX(num, x):
d = num // x
a = d * x
b = a + x
if b - num <= num - a:
return b
else:
return a
e.g.
for i in range(10):
print(i, nearestX(i, 3))
0 0
1 0
2 3
3 3
4 3
5 6
6 6
7 6
8 9
9 9

Time and memory limit exceeded - Python3 - Number Theory

I am trying to find the sum of the multiples of 3 or 5 of all the numbers upto N.
This is a practise question on HackerEarth. I was able to pass all the test cases except 1. I get a time and memory exceeded error. I looked up the documentation and learnt that int can handle large numbers and the type bignum was removed.
I am still learning python and would appreciate any constructive feedback.
Could you please point me in the right direction so I can optimise the code myself?
test_cases = int(input())
for i in range(test_cases):
user_input = int(input())
sum = 0
for j in range (0, user_input):
if j % 3 == 0:
sum = sum + j
elif j % 5 == 0:
sum = sum + j
print(sum)
In such problems, try to use some math to find a direct solution rather than brute-forcing it.
You can calculate the number of multiples of k less than n, and calculate the sum of the multiples.
For example, with k=3 and n=13, you have 13 // 3 = 4 multiples.
The sum of these 4 multiples of 3 is 3*1 + 3*2 + 3*3 + 3*4 = 3 * (1+2+3+4)
Then, use the relation: 1+2+....+n = n*(n+1)/2
To sum the multiples of 3 and 5, you can sum the multiples of 3, add the sum of the multiples of 5, and subtract the ones you counted twice: the multiples of 15.
So, you could do it like this:
def sum_of_multiples_of(k, n):
"""
Returns the sum of the multiples of k under n
"""
# number of multiples of k between 1 and n
m = n // k
return k * m * (m+1) // 2
def sum_under(n):
return (sum_of_multiples_of(3, n)
+ sum_of_multiples_of(5, n)
- sum_of_multiples_of(15, n))
# 3+5+6+9+10 = 33
print(sum_under(10))
# 33
# 3+5+6+9+10+12+15+18 = 78
print(sum_under(19))
# 78

Resources