I have a fragment of my code where i wrote functions to check rows, column and diagonal for the queen placement so that they will not attack each other. Currently I'm having issues with the diagonal function:
def checkDiagonal(T):
for i in range(len(T) - 1):
if abs(T[i] - T[i + 1]) == 1:
return False
return True
The problem with this function is that it will only consider when queens are one length apart but not when cases more than one.
Example, if N = 7 it prints:
Enter the value of N: 7
0 Q 0 0 0 0 0
0 0 0 0 0 0 0
0 0 X 0 0 0 0
0 0 X 0 0 0 0
0 0 X 0 0 0 0
0 0 X 0 0 0 0
Q 0 0 0 0 0 0
the Q in the output is the partial solution i set in the code. The X is the next possible position for the queen but there is one X in the output that is clearly diagonal to the queen and will be attacked.
Partial solution list = [6,0], in this case it will be passed to the function as T
Two points (x1, y1) and (x2, y2) are one the same lower left -> upper right diagonal if and only if y1 - x1 == y2 - x2.
If I understand you question correctly, the partial solution T = [0,6] would represent the partial solution [(0,0), (1,6)]. So, since 0 - 0 = 0 != 5 == 6 - 1 , these two elements are not on the same diagonal.
However, for the partial solution [0 , 6, 2] = [(0,0), (1,6), (2,2)] we would have 0 - 0 == 0 == 2 - 2 and hence the two points would be on the same lower left -> upper right diagonal.
For the upper left -> lower right diagonal you would then have to find a similar condition, which I think you should be able to figure out, but let me know if you don't manage to find it.
This would lead to something like the code (only for this diagonal):
def checkDiagonal(T):
for i in xrange(len(T) - 1):
for j in xrange(i + 1, len(T))
if ((T[i] - i == T[j] - j):
return false
return true
Be careful however that I didn't have time to test this, so there might be small errors in it, but the general idea should be right.
Related
I would like to rearrange the indices in a tuple which was created with np.where.
The reason for this is, that I would like to apply values to a number of special position (a pipe) in a mesh, which were pre-selected. The values shall be applied in the direction of flow. The direction of flow is defined from top left to bottom left = from (3,0) to (3,6) to (7,6) to (7,0). Currently, the order of the index tuple ind is according to the automatic sorting of the indices. This leads to the figure, below, where the values 1:10 are correctly applied, but 11:17 are obviously in reverse order.
Is there a better way to grab the indices or how can I rearrange the tuple so that the values are applied in the direction of flow?
import numpy as np
import matplotlib.pyplot as plt
# mesh size
nx, ny = 10, 10
# special positions
sx1, sx2, sy = .3, .7, .7
T = 1
# create mesh
u0 = np.zeros((nx, ny))
# assign values to mesh
u0[int(nx*sx1), 0:int(ny*sy)] = T
u0[int(nx*sx2), 0:int(ny*sy)] = T
u0[int(nx*sx1+1):int(nx*sx2), int(ny*sy-1)] = T
# get indices of special positions
ind = np.where(u0 == T)
# EDIT: hand code sequence
length = len(u0[int(nx*sx2), 0:int(ny*sy)])
ind[0][-length:] = np.flip(ind[0][-length:])
ind[1][-length:] = np.flip(ind[1][-length:])
# apply new values on special positions
u0[ind] = np.arange(1, len(ind[1])+1,1)
fig, ax = plt.subplots()
fig = ax.imshow(u0, cmap=plt.get_cmap('RdBu_r'))
ax.figure.colorbar(fig)
plt.show()
Old image (without edit)
New image (after edit)
I think it's a fallacy to think that you can algorithmically deduce the correct "flow-sequence" of the grid points, by examining the contents of the tuple ind.
Here's an example that illustrates why:
0 0 0 0 0 0 0 0 0 0
A B C D E 0 0 0 0 0
0 0 0 0 F 0 0 0 0 0
0 0 0 0 G 0 0 0 0 0
0 0 0 I H 0 0 0 0 0
0 0 0 J K 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
This is a schematic representation of your grid matrix, where, if you follow the letters A, B, C, etc, you will get the sequence of the flow through the grid-elements.
However, note that, no matter how smart an algorithm is, it will be unable to choose between the two possible flows:
A, B, C, D, E, F, G, H, I, J, K
and
A, B, C, D, E, F, G, H, K, J, I
So, I think you will have to record the sequence explicitly yourself, rather than deduce it from the positions of the T values in the grid.
Any algorithm will stop at the ambiguity at the grid location H in the above example
Recently for a school project i've been making a "Treasure hunt" where the player finds treasure and bandits on a grid in python. I have a way to have the grid at a set size but, as an extra point they ask for us to be able to change the size of the grid, the amount of chests and the amount of bandits.
Here is the code for my grid maker but it wont make the "grid" array but it does for "playergrid":
def gridmaker(gridsize, debug):
global grid
global playergrid
gridinator = 1
grid = [[0]]
playergrid = [[" "]]
if debug == 1:
while gridinator <= gridsize:
grid[gridinator].append(0)
gridinator = gridinator + 1
gridinator = 1
else:
while gridinator <= gridsize:
playergrid[0].append(gridinator)
gridinator = gridinator + 1
gridinator = 1
while gridinator <= gridsize:
if debug == 1:
grid.append([0])
for i in range(gridsize):
grid[gridinator].append(0)
else:
playergrid.append([gridinator])
for i in range(gridsize):
playergrid[gridinator].append("#")
gridinator = gridinator+1
if debug == 1:
grid[1][1] = 1
else:
playergrid[1][1] = "P"
gridmaker(9, 1)
for row in grid:
print(" ".join(map(str,row)))
Sorry if it is formatted differently as there are 2 space tabs rather than 4, it works best on repl.it
print(grid) should return a grid like this:
0 0 0 0 0 0 0 0 0
0 1 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
Please let me know,
Thanks!
You have to remember that lists are 0-indexed.
Which means that to access the 1st element of the grid list you would use the index 0.
With grid = [[0]] you create a list with one item (you can get that item with grid[0]), which is a list whose 1st item (grid[0][0]) is 0.
But your gridinator's starting value is 1. So when your first append runs:
grid[gridinator].append(0)
it tries to access the 2nd element of grid:
grid[1].append(0)
Which gives you an IndexError since, as the traceback should tell you* list index out of range.
You can try this yourself:
grid = [[0]]
grid[0]
grid[1]
One of your solutions could be starting the gridinator with 0, and using strict less instead of less or equal here: gridinator <= gridsize (because grid[8] gives you the 9th element of the grid).
*Please remember to include the traceback for errors in the future. They really help both yourself and the people trying to help you.
Let me know if this helps, or if I should find another way to explain it.
What I'm trying to do is have a 2D array and for every coordinate in the array, ask all the other 8 coordinates around it if they have stored a 1 or a 0. Similar to a minesweeper looking for mines.
I used to have this:
grid = []
for fila in range(10):
grid.append([])
for columna in range(10):
grid[fila].append(0)
#edited
for fila in range (10):
for columna in range (10):
neighbour = 0
for i in range 10:
for j in range 10:
if gird[fila + i][columna + j] == 1
neighbour += 1
But something didn't work well. I also had print statments to try to find the error that way but i still didnt understand why it only made half of the for loop. So I changed the second for loop to this:
#edited
for fila in range (10):
for columna in range (10):
neighbour = 0
if grid[fila - 1][columna - 1] == 1:
neighbour += 1
if grid[fila - 1][columna] == 1:
neighbour += 1
if grid[fila - 1][columna + 1] == 1:
neighbour += 1
if grid[fila][columna - 1] == 1:
neighbour += 1
if grid[fila][columna + 1] == 1:
neighbour += 1
if grid[fila + 1][columna - 1] == 1:
neighbour += 1
if grid[fila + 1][columna] == 1:
neighbour += 1
if grid[fila + 1][columna + 1] == 1:
neighbour += 1
And got this error:
if grid[fila - 1][columna + 1] == 1:
IndexError: list index out of range
It seems like I can't add on the grid coordinates but I can subtract. Why is that?
Valid indices in python are -len(grid) to len(grid)-1. the positive indices are accessing elements with offset from the front, the negative ones from the rear. adding gives a range error if the index is greater than len(grid)-1 that is what you see. subtracting does not give you a range error unless you get an index value less than -len(grid). although you do not check for the lower bound, which is 0 (zero) it seems to work for you as small negative indices return you values from the rear end. this is a silent error leading to wrong neighborhood results.
If you are computing offsets, you need to make sure your offsets are within the bounds of the lists you have. So if you have 10 elements, don't try to access the 11th element.
import collections
grid_offset = collections.namedtuple('grid_offset', 'dr dc')
Grid = [[0 for c in range(10)] for r in range(10)]
Grid_height = len(Grid)
Grid_width = len(Grid[0])
Neighbors = [
grid_offset(dr, dc)
for dr in range(-1, 2)
for dc in range(-1, 2)
if not dr == dc == 0
]
def count_neighbors(row, col):
count = 0
for nb in Neighbors:
r = row + nb.dr
c = col + nb.dc
if 0 <= r < Grid_height and 0 <= c < Grid_width:
# Add the value, or just add one?
count += Grid[r][c]
return count
Grid[4][6] = 1
Grid[5][4] = 1
Grid[5][5] = 1
for row in range(10):
for col in range(10):
print(count_neighbors(row, col), "", end='')
print()
Prints:
$ python test.py
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 1 1 1 0 0
0 0 0 1 2 3 1 1 0 0
0 0 0 1 1 2 2 1 0 0
0 0 0 1 2 2 1 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
The error is exactly what it says, you need to check if the coordinates fit within the grid:
0 <= i < 10 and 0 <= j < 10
Otherwise you're trying to access an element that doesn't exist in memory, or an element that's not the one you're actually thinking about - Python handles negative indexes, they're counted from the end.
E.g. a[-1] is the last element, exactly the same as a[len(a) - 1].
I'm trying to write an algorithm that will find the path in n*n matrix with minimum cost (every coordinate has a pre-defined cost). Cost of path is defined as the sum of all coordinate costs. The first line of input contains the size of a matrix and the following n lines are table rows. Last two lines of code are 1. begin coordinates 2. end coordinates. Output is the minimum path cost.
Example input :
5
0 1 2 1 1
0 0 1 5 1
1 0 0 1 1
1 1 0 7 0
1 8 0 0 0
0 0
4 4
Output should be 0
This is code with memoization (it works without memoization but it's slow)
import copy
import sys
sys.setrecursionlimit(9000)
INF = 100000
n = int(input())
memo = {}
def input_matrix(n) :
p = []
for i in range(n) :
p.append(list(map(int, input().split())))
return p
def min_cost(matrix, x, y, end_x, end_y) :
if x == end_x and y == end_y :
return 0
if (x, y) in memo :
return memo[(x, y)]
if x == len(matrix) or y == len(matrix) or x == -1 or y == -1 or matrix[y][x] == -1:
return INF
z = copy.deepcopy(matrix)
z[y][x] = -1
memo[(x, y)] = min(
min_cost(z, x+1, y, end_x, end_y)+matrix[y][x],
min_cost(z, x-1, y, end_x, end_y)+matrix[y][x],
min_cost(z, x, y+1, end_x, end_y)+matrix[y][x],
min_cost(z, x, y-1, end_x, end_y)+matrix[y][x]
)
return memo[(x, y)]
matrix = input_matrix(n)
begin_coords = list(map(int, input().split()))
end_coords = list(map(int, input().split()))
print(min_cost(matrix, begin_coords[0], begin_coords[1], end_coords[0], end_coords[1]))
The problem is that your use of the cache is not correct. Consider the following example, in which your code returns 1 instead of 0:
3
0 0 1
1 0 0
1 1 0
0 0
2 2
If you try to follow the code flow you'll see that your algorithms searches the matrix in the following way:
0 -> 0 -> 1 -> x
|
1 <- 0 <- 0 -> x
|
1 -> 1 -> 0
Moreover you are setting the value in the matrix at -1 when you perform the recursive call, so when you finally reach the goal the matrix is:
-1 -1 -1
-1 -1 -1
-1 -1 0
Sure, you are copying the matrices, but during a recursive call the whole path followed to reach that point will still be -1.
I.e. when your code finds 2, 2 it returns 0. The call on 1, 2 tries to compute the value for 0, 2 but returns inf because the bottom-left corner is -1, the call on 1, 3 and 1, 1 return +inf too. So for x=1, y=2 we get the correct value 1. The code backtracks, obtaining the matrix:
-1 -1 -1
-1 -1 -1
-1 1 0
And we have 1,2 -> 1 in our memo. We have to finish the call for 0, 2, which again tries -1, 2, 0, 3 and 0, 1 all of these return +inf and hence we compute 0 2 -> 2 which is correct.
Now however things start to go wrong. The call at 0, 1 has already tried to go 1, 1 but that returns +inf since the value is set to -1, the same holds for all other recursive calls. Hence we set 0, 1 -> 3 which is wrong.
Basically by setting the value in the matrix to -1 during recursive calls you have prevent the recursive call for 0, 1 to go right and get the correct value of 1.
The issue appears in the cached version because now *every time we return to 0 1 we get the wrong value. Without cache the code is able to reach 0 1 by a path not coming from 1 1 and hence discover that 0 1 -> 1.
Instead of cachine I would use a dynamic programming approach. Fill the matrix with +inf values. Start at the goal position and put a 0 there, then compute the neighbouring values by row/column:
def min_cost(matrix, x, y, end_x, end_y):
n = len(matrix)
memo = [[float('+inf') for _ in range(n)] for _ in range(n)]
memo[end_y, end_x] = 0
changed = True
while changed:
changed = False
for x in range(n):
for y in range(n):
m = matrix[y][x]
old_v = memo[y][x]
memo[y][x] = min(
memo[y][x],
m + min(memo[h][k] for h in (y-1, y+1) if 0 <= h < n for k in (x-1, x+1) if 0 <= k < n)
)
if memo[y][x] != old_v:
changed = True
return memo[y, x]
However this is still not as efficient as it could be. If you apply dynamic programming correctly you will end up with the Bellman-Ford Algorithm. Your grid is just a graph where each vertex x, y has four outgoing edges (except those on the border).
Say I have an MxN matrix of 0's and 1's. It may or may not be sparse.
I want a function to efficiently find rectangles in the array, where by rectangle I mean:
a set of 4 elements that are all 1's that create the 4 corners of a
rectangle, such that the sides of the rectangle are orthogonal to the
array axes. In other words, a rectangle is a set of 4 1's elements
with coordinates [row index, column index] like so: [r1,c1], [r1,c2],
[r2,c2], [r2,c1].
E.g. this setup has one rectangle:
0 0 0 1 0 1 0
0 0 0 0 0 0 0
0 1 0 0 0 0 0
1 0 0 1 0 1 0
0 0 0 0 0 0 0
0 0 0 1 0 0 1
For a given MxN array, I want a Python function F(A) that returns an array L of subarrays, where each subarray is the coordinate pair of the corner of a rectangle (and includes all of the 4 corners of the rectangle). For the case where the same element of the array is the corner of multiple rectangles, it's ok to duplicate those coordinates.
My thinking so far is:
1) find the coordinates of the apex of each right triangle in the array
2) check each right triangle apex coordinate to see if it is part of a rectangle
Step 1) can be achieved by finding those elements that are 1's and are in a column with a column sum >=2, and in a row with a row sum >=2.
Step 2) would then iterate through each coordinate determined to be the apex of a right triangle. For a a given right triangle coordinate pair, it would iterate through that column, looking at every other right triangle coordinate from 1) that is in that column. For any pair of 2 right triangle points in a column, it would then check which row has a smaller row sum to know which row would be faster to iterate through. Then it would iterate through all of the right triangle column coordinates in that row and see if the other row also has a right triangle point in that column. If it does, those 4 points form a rectangle.
I think this will work, but there will be repetition, and overall this procedure seems like it would be reasonably computationally intensive. What are some better ways for detecting rectangle corners in 0-1 arrays?
This is from the top of my head and during 5 hrs layover at LAX. Following is my algorithm:
Step 1: Search all rows for at least two ones
| 0 0 0 1 0 1 0
| 0 0 0 0 0 0 0
| 0 1 0 0 0 0 0
\|/ 1 0 0 1 0 1 0
0 0 0 0 0 0 0
0 0 0 1 0 0 1
Output:
-> 0 0 0 1 0 1 0
0 0 0 0 0 0 0
0 1 0 0 0 0 0
-> 1 0 0 1 0 1 0
0 0 0 0 0 0 0
-> 0 0 0 1 0 0 1
Step 2: For each pair of ones at each row get the index for one's in the column corresponding to the ones, lets say for the first row:
-> 0 0 0 1 0 1 0
you check for ones in the following columns:
| |
\|/ \|/
0 0 0 1 0 1 0
0 0 0 0 0 0 0
0 1 0 0 0 0 0
1 0 0 1 0 1 0
0 0 0 0 0 0 0
0 0 0 1 0 0 1
Step 3: If both index match; return the indices of all four. This can be easily accessed as you know the row and index of ones at all steps. In our case the search at columns 3, 5 are going to return 3 assuming you start index from 0. So we get the indicies for the following:
0 0 0 ->1 0 ->1 0
0 0 0 0 0 0 0
0 1 0 0 0 0 0
1 0 0 ->1 0 ->1 0
0 0 0 0 0 0 0
0 0 0 1 0 0 1
Step 4: Repeat for all pairs
Algorithm Complexity
I know you need to search for columns * rows * number of pairs but you can always use hashmaps to optimize search O(1). Which will make over complexity bound to the number of pairs. Please feel free to comment with any questions.
Here's an Python implementation which is similar to #PseudoAj solution. It will process the rows starting from top while constructing a dict where keys are x coordinates and values are sets of respective y coordinates.
For every row following steps are done:
Generate a list of x-coordinates with 1s from current row
If length of list is less than 2 move to next row
Iterate over all coordinate pairs left, right where left < right
For every coordinate pair take intersection from dict containing processed rows
For every y coordinate in the intersection add rectangle to result
Finally update dict with coordinates from current row
Code:
from collections import defaultdict
from itertools import combinations
arr = [
[0, 0, 0, 1, 0, 1, 0],
[0, 0, 0, 0, 0, 0, 0],
[0, 1, 0, 0, 0, 0, 0],
[1, 0, 0, 1, 0, 1, 0],
[0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 1, 0, 0, 1]
]
# List corner coords
result = []
# Dict {x: set(y1, y2, ...)} of 1s in processed rows
d = defaultdict(set)
for y, row in enumerate(arr):
# Find indexes of 1 from current row
coords = [i for i, x in enumerate(row) if x]
# Move to next row if less than two points
if len(coords) < 2:
continue
# For every pair on this row find all pairs on previous rows
for left, right in combinations(coords, 2):
for top in d[left] & d[right]:
result.append(((top, left), (top, right), (y, left), (y, right)))
# Add coordinates on this row to processed rows
for x in coords:
d[x].add(y)
print(result)
Output:
[((0, 3), (0, 5), (3, 3), (3, 5))]