Number of Edges - python

You are given a grid ; having n rows ; and mcolumns ; where two cells are called to be adjacent if : they have a common side.
let two adjacent cells be a and b . Since they are adjacent ; hence ; you may go both from a to b ; and also from b to a.
In terms of graph theory ; we may say that if the grid is modelled as a directed graph ; then, there exists a directed edge from a to b ; and also a from b to ; in case cells a and b are adjacent.
You are asked to find the number of directed edges in the graph.
Input Format
The first line of the input contains a single integer T ; denoting the number of test cases.
Then ;t lines follow ; where each line contains two space seperated integers n and m ; the dimensions of the grid respectively.
Sample Input 0
1
3 3
Sample Output 0
24
Explanation 0
Number of the directed edges is 24.
Is this approach correct ? My code did passes the sample test cases but fails for others
def compute(m,n):
arr = [[0 for x in range(n)] for y in range(m)]
arr[0][0]=2
arr[n-1][m-1]=2
arr[0][m-1]=2
arr[n-1][0]=2
for i in range (1,m-1):
arr[i][0]=3
arr[i][n-1]=3
for j in range (1,n-1):
arr[0][j]=3
arr[n-1][j]=3
for i in range (1,n-2):
for j in range (1,m-2):
arr[i][j]=4
return sum(sum(arr,[])) +4
Please explain the correct approach for this problem.Thanks in advance

For a grid of n rows and m columns: the number of sides in any row is m-1, the number of sides in any column is n-1. Every side has two edges in the graph of adjacent cells.
Therefore the number of edges for an n*m grid is:
def compute(n, m):
return n * (m - 1) * 2 + m * (n - 1) * 2
Or, simplified even further:
def compute(n, m):
return 4 * n * m - 2 * n - 2 * m
Your algorithm goes and fills in the individual edges to sum them at the end, which is far more complicated than it needs to be for this problem without additional constraints.

I think you can solve this with dynamic programming.
number of edge in m*n = number of edge in (m-1)*(n) + to_be_calculated
Then you can simply find the amount of to_be_calculated by 2*n + 2*(n-1)
After you finished with columns and reached to m == 1 then you can reduce n to 1.
def compute(n,m,sum):
if n == 1 and m == 1:
return sum
elif m == 1:
return compute(1, 1, sum + 2*(n-1))
else:
return compute(n, m-1, sum + 2*n + 2*(n-1) )
compute(5,5,0) # For table 5x5

You can find a formula to compute the number of edges in the graph as follows:
Suppose we have a grid with dimensions n and m. For each cell we need to count the number of neighbor cells. Then, the summation of such numbers is the number of edges.
Case 1) such a grid has 4 corner cells each with 2 neighbors; total neighbors case 1: 4*2=8
Case 2: such a grid has 2(n+m-2)-4 cells in its sides exclude the corners each with 3 neighbors, total neighbors case 2: (2(n+m-2)-4)3
Case 3) such a grid has nm-(2(n+m-2)-4)-4 inner cells each with 4 neighbors, total neighbors case 3: *(nm-(2(n+m-2)-4)-4)4
Total number of edges = Case 1 + Case 2 + Case 3 = 8 + (2(n+m-2)-4)3 + (nm-(2(n+m-2)-4)-4)4 = 4nm - 2(n+m)
The figure below displays all the cases:
So you can use the code below to compute the number of edges:
def compute_total_edges(m,n):
return 4*n*m-2*(n+m)
print(compute_total_edges(3,3))

Related

maximum difference in the summation of two subset

I have an array with N elements. I have to divide the array into two subset such that one subset has exactly M elements and the other subset has the rest. Dividing the items into subset in a way such that the difference in the summation of elements between the two subset is the maximum.
Example:
array size, N = 6
Number of element in one group, M = 3
elements = {2, 6, 3, 5, 10, 4}
The summation of subset 1 = 2 + 3 + 4 = 9
The summation of subset 2 = 6+ 5 + 10 = 21
The difference in subset = 21 - 9 = 12.
Note, this is the maximum difference possible.
I wrote following logic in python.
items = list(map(int, input().split()))
items.sort()
left = items[:M]
right = items[M:]
print(sum(right)-sum(left))
Not working when my input array is {100, 100, 150} and M = 2; Its giving me answer 50. But correct answer will be 150.
Constraints
1<= N <=1000 // N is size of array
1<= M < N // M is the size of subset
1<= array element <=10000000 // elements
What will be the approach to solve this problem?
You need to sort first which you got it. Now you can take M elements from either from start or from the end. Consider both cases and take max.
items.sort()
left_sum = sum(items[:M])
left_sum_2 = sum(items[:-M])
right_sum = sum(items)-left
right_sum_2 = sum(items)-left_sum_2
print(max(abs(right_sum_2-left_sum_2), abs(right_sum-left_sum)))
I suppose you should check two cases: the difference between the M lowest elements and the N-M highest ones, as you already did; and instead the difference between the M highest and the N-M lowest. Just return the biggest of the two. This is still O(n log n) by the way

Generate an Asymmetric NxM matrix whose Rows and Columns Independently Sum to 1

Given a target matrix size of N rows and M columns, is it possible to pick values such that all rows and columns sum to 1, on the condition that the matrix is not symmetric across the diagonal? Here's a target matrix I was able to generate when N==M (The problems arise when N!=M - see below):
[[0.08345877 0.12844672 0.90911941 0.41964704 0.57709569]
[0.53949086 0.07965491 0.62582134 0.48922244 0.38357809]
[0.80619328 0.27581426 0.31312973 0.26855717 0.4540732 ]
[0.11803505 0.88201276 0.1990759 0.2818701 0.63677383]
[0.57058968 0.75183898 0.07062126 0.6584709 0.06624682]]
I'm writing this in numpy. Currently I've written the following (brute force) code, which I know works when n==m. However, if n != m, rowwise and columwise sums don't converge to 0, and the ratio of rowwise sums to columwise sums converges to (n/m):
n,m = (5,4)
mat = np.random.random((n,m))
for i in range(100):
s0 = mat.sum(0)
s1 = mat.sum(1)[:,newaxis]
mat = (mat/s0)
mat = (mat/s1)
if i%10 == 0:
print(s0[0]/s1[0,0])
The final output in this case is 1.25 (I.e. n/m, or 5/4). I'm beginning to think this might not be mathematically possible. Can someone prove me wrong?
I suspect you are correct, the problem cannot be solved if N != M.
Take a 2x3 matrix as an example:
[[a b c]
[d e f]]
Assume that all rows and all columns sum to 1 and show a contradiction. The rows sum to 1 so:
a+b+c = 1
d+e+f = 1
This gives:
(a+b+c)+(d+e+f) = 1 + 1 = 2
Now look at the columns. Each column also sums to 1 so we have:
a+d = 1
b+e = 1
c+f = 1
Combining the three column equations gives:
(a+d)+(b+e)+(c+f) = 1 + 1 + 1 = 3
Since the sum of all six matrix elements cannot be both 2 and 3 simultaneously, 2 != 3, the initial assumption leads to a contradiction and so is disproved. More generally the problem cannot be solved for N != M with N rows and M columns.
The contradiction disappears when N = M for a square matrix.

How to optimize (3*O(n**2)) + O(n) algorithm?

I am trying to solve the arithmetic progression problem from USACO. Here is the problem statement.
An arithmetic progression is a sequence of the form a, a+b, a+2b, ..., a+nb where n=0, 1, 2, 3, ... . For this problem, a is a non-negative integer and b is a positive integer.
Write a program that finds all arithmetic progressions of length n in the set S of bisquares. The set of bisquares is defined as the set of all integers of the form p2 + q2 (where p and q are non-negative integers).
The two lines of input are n and m, which are the length of each sequence, and the upper bound to limit the search of the bi squares respectively.
I have implemented an algorithm which correctly solves the problem, yet it takes too long. With the max constraints of n = 25 and m = 250, my program does not solve the problem in the 5 second time limit.
Here is the code:
n = 25
m = 250
bisq = set()
for i in range(m+1):
for j in range(i,m+1):
bisq.add(i**2+j**2)
seq = []
for b in range(1, max(bisq)):
for a in bisq:
x = a
for i in range(n):
if x not in bisq:
break
x += b
else:
seq.append((a,b))
The program outputs the correct answer, but it takes too long. I tried running the program with the max n/m values, and after 30 seconds, it was still going.
Disclaimer: this is not a full answer. This is more of a general direction where to look for.
For each member of a sequence, you're looking for four parameters: two numbers to be squared and summed (q_i and p_i), and two differences to be used in the next step (x and y) such that
q_i**2 + p_i**2 + b = (q_i + x)**2 + (p_i + y)**2
Subject to:
0 <= q_i <= m
0 <= p_i <= m
0 <= q_i + x <= m
0 <= p_i + y <= m
There are too many unknowns so we can't get a closed form solution.
let's fix b: (still too many unknowns)
let's fix q_i, and also state that this is the first member of the sequence. I.e., let's start searching from q_1 = 0, extend as much as possible and then extract all sequences of length n. Still, there are too many unknowns.
let's fix x: we only have p_i and y to solve for. At this point, note that the range of possible values to satisfy the equation is much smaller than full range of 0..m. After some calculus, b = x*(2*q_i + x) + y*(2*p_i + y), and there are really not many values to check.
This last step prune is what distinguishes it from the full search. If you write down this condition explicitly, you can get the range of possible p_i values and from that find the length of possible sequence with step b as a function of q_i and x. Rejecting sequences smaller than n should further prune the search.
This should get you from O(m**4) complexity to ~O(m**2). It should be enough to get into the time limit.
A couple more things that might help prune the search space:
b <= 2*m*m//n
a <= 2*m*m - b*n
An answer on math.stackexchange says that for a number x to be a bisquare, any prime factor of x of the form 3 + 4k (e.g., 3, 7, 11, 19, ...) must have an even power. I think this means that for any n > 3, b has to be even. The first item in the sequence a is a bisquare, so it has an even number of factors of 3. If b is odd, then one of a+1b or a+2b will have an odd number of factors of 3 and therefore isn't a bisquare.

Fast algorithm to compute Adamic-Adar

I'm working on graph analysis. I want to compute an N by N similarity matrix that contains the Adamic Adar similarity between every two vertices. To give an overview of Adamic Adar let me start with this introduction:
Given the adjacency matrix A of an undirected graph G. CN is the set of all common neighbors of two vertices x, y. A common neighbor of two vertices is one where both vertices have an edge/link to, i.e. both vertices will have a 1 for the corresponding common neighbor node in A. k_n is the degree of node n.
Adamic-Adar is defined as the following:
My attempt to compute it is to fetch both rows of the x and y nodes from A and then sum them. Then look for the elements that has 2 as the value and then gets their degrees and apply the equation. However computing that takes really really a long of time. I tried with a graph that contains 1032 vertices and it took a lot of time to compute. It started with 7 minutes and then I cancelled the computations. So my question: is there a better algorithm to compute it?
Here's my code in python:
def aa(graph):
"""
Calculates the Adamic-Adar index.
"""
N = graph.num_vertices()
A = gts.adjacency(graph)
S = np.zeros((N,N))
degrees = get_degrees_dic(graph)
for i in xrange(N):
A_i = A[i]
for j in xrange(N):
if j != i:
A_j = A[j]
intersection = A_i + A_j
common_ns_degs = list()
for index in xrange(N):
if intersection[index] == 2:
cn_deg = degrees[index]
common_ns_degs.append(1.0/np.log10(cn_deg))
S[i,j] = np.sum(common_ns_degs)
return S
Since you're using numpy, you can really cut down on your need to iterate for every operation in the algorithm. my numpy- and vectorized-fu aren't the greatest, but the below runs in around 2.5s on a graph with ~13,000 nodes:
def adar_adamic(adj_mat):
"""Computes Adar-Adamic similarity matrix for an adjacency matrix"""
Adar_Adamic = np.zeros(adj_mat.shape)
for i in adj_mat:
AdjList = i.nonzero()[0] #column indices with nonzero values
k_deg = len(AdjList)
d = np.log(1.0/k_deg) # row i's AA score
#add i's score to the neighbor's entry
for i in xrange(len(AdjList)):
for j in xrange(len(AdjList)):
if AdjList[i] != AdjList[j]:
cell = (AdjList[i],AdjList[j])
Adar_Adamic[cell] = Adar_Adamic[cell] + d
return Adar_Adamic
unlike MBo's answer, this does build the full, symmetric matrix, but the inefficiency (for me) was tolerable, given the execution time.
I believe you are using rather slow approach. It would better to revert it -
- initialize AA (Adamic-Adar) matrix by zeros
- for every node k get it's degree k_deg
- calc d = log(1.0/k_deg) (why log10 - is it important or not?)
- add d to all AAij, where i,j - all pairs of 1s in kth row
of adjacency matrix
Edit:
- for sparse graphs it is useful to extract positions of all 1s in kth row to the list to reach O(V*(V+E)) complexity instead of O(V^3)
AA = np.zeros((N,N))
for k = 0 to N - 1 do
AdjList = []
for j = 0 to N - 1 do
if A[k, j] = 1 then
AdjList.Add(j)
k_deg = AdjList.Length
d = log(1/k_deg)
for j = 0 to AdjList.Length - 2 do
for i = j+1 to AdjList.Length - 1 do
AA[AdjList[i],AdjList[j]] = AA[AdjList[i],AdjList[j]] + d
//half of matrix filled, it is symmetric for undirected graph
I don't see a way of reducing the time complexity, but it can be vectorized:
degrees = A.sum(axis=0)
weights = np.log10(1.0/degrees)
adamic_adar = (A*weights).dot(A.T)
With A a regular Numpy array. It seems you're using graph_tool.spectral.adjacency and thus A would be a sparse matrix. In that case the code would be:
from scipy.sparse import csr_matrix
degrees = A.sum(axis=0)
weights = csr_matrix(np.log10(1.0/degrees))
adamic_adar = A.multiply(weights) * A.T
This is much faster than using Python loops. A small warning though: with this approach you really need to make sure that the values on the main diagonal (of A and adamic_adar) are what you expect them to be. Also, A must not contain weights, but only zeros and ones.
I believe there most be a function like the one defined in R igraph in its python_igraph as well for the node similarity (Adamic_Adar as well)

Finding a number of unique paths from one corner of the board to the other without backtracking

I am stuck with a algorithm optimization.
The goal is to find how many different ways your can use to go from a point A to a point B in a chess board where :
A is the bottom left square.
B is the top right square.
piece can go only one up or one right each turn.
Here is a dummy solution :
# -*- conding: utf-8 -*-
import time
def solution(n, m, x, y):
ret = 0
if x < n-1:
ret += solution(n, m, x+1, y)
if y < m-1:
ret += solution(n, m, x, y+1)
if x == n-1 and y == m-1:
ret = 1
return ret
def wrapper(n, m):
start = time.time()
reponse = solution(n, m, 0, 0)
stop = time.time()
print "Response: %dx%d = %d\nTime : %f\n" % (n, m, reponse, stop-start)
if __name__ == "__main__":
for i in range(10):
wrapper(i+1,i+1)
#wrapper(7,7)
#wrapper(10,10)
#wrapper(100,100)
#wrapper(1000,1000)
#wrapper(10000,10000) <- way too slow
While I stay with small chess boards, it works fine and results are relevant. But my goal is to find a solution for a 10000x10000 board.
Does anyboy have an idea ?
Think of it this way: since your points A and B are at the same place, you have to move the same amount of UPs and RIGHTs, but the the order will be different. So you need to find the amount of different combinations.
Dynamic Programming: O(N)
It has already mentioned that the problem has a solution by using a Triangle of Pascal, and its relation to the Binomial coefficient. Also the Catalan number's entry has a nice illustration for the n × n case.
n × n case
By making use of the aforementioned resources you can conclude that for a grid of size n × n you need to calculate C(2n - 2, n - 1). You can double-check it by rotating the grid by 45 degrees and mapping the Pascal's Triangle.
In practical terms, calculating this number directly requires to calculate, in a naive way, at most 3 different factorials which is a very expensive task. If you can pre-calculate them all then there's no discussion here and you can argue this problem has complexity O(1). If you are not interested in the pre-calculated way then you can continue reading.
You can calculate such ominous number using Dynamic Programming (DP). The trick here is to perform the operation in smaller steps which won't require you to calculate a large factorial number at all.
That is, to calculate C(n, k), you can start by placing yourself at C(n, 1) and walk to C(n, k). Let's start by defining C(n, k) in terms of C(n, k - 1).
C(n, k) = n! / k! * ( n - k )! ; k! = (k - 1)! * k
= n! / (k - 1)! * k * (n - k)! ; (n - k)! = (n - k + 1)! / (n - k + 1)
= n! * (n - k + 1) / (k - 1)! * k * (n - k + 1)! ; C(n, k - 1) = n! / (k - 1)! * ( n - k + 1 )!
= C(n, k - 1) * (n - k + 1) / k
Based on this, you can define a function to calculate C(n, k) as follows in Python:
def C(n, k):
"""
Calculate C(n, k) using Dynamic Programming.
C(n, k) = C(n, k - 1) * (n - k + 1) / k
"""
C = 1
for ki in range(1, k + 1):
C = C * (n - ki + 1) / ki
return C
It runs in linear time, O(N).
For the n × n case you need to calculate C(2n - 2, n - 1).
>> print "Response: %dx%d = %d" % (n, n, C(2 * n - 2, n - 1),)
Response: 10000x10000 = 5...
n × m case
For the general n × m case, you just need to calculate C(n + m - 2, m - 1).
>> print "Response: %dx%d = %d" % (n, m, C(n + m - 2, m - 1),)
Response: 10000x10000 = 5...
Last but not least, you can see a live example at Ideone here.
Timings
I ran the algorithm for the following grid sizes.
N x N | Response's Length | Time
-----------------+-------------------+-----------
1 x 1 | 1 chars | 0.000001
10 x 10 | 5 chars | 0.000004
100 x 100 | 59 chars | 0.000068
1000 x 1000 | 600 chars | 0.002207
10000 x 10000 | 6018 chars | 0.163647
100000 x 100000 | 60203 chars | 40.853971
It seems the operations above a grid size of 100 000 x 100 000 get absurdly expensive due to the very large numbers involved. Nothing to be surprised though.
You do not need an algorithm for this. Just math. Here's something to think about: when you are on the top-right square, you don't have any different options. Let's count that as zero. When you are just to the right of the top-right corner, your only choice is to go right (one option), since you are not allowed to backtrack. When you are just below the top-right corner, your only choice is to go up. Let's map that out
... 1 0
..... 1
What about the corner to the left/down from the target corner. From there, there are two paths to the corner (sum of the options to get to the neighbours): you can go up to right:
... 1 0
....2 1
Expanding the edges we expand always with ones: once you are at the top, there is only one way to get to the top-right:
...1 1 1 0
...... 2 1
........ 1
........=1
But each non-edge choice is a sum of the numbers in the north and east neighbours:
...1 1 1 0
.....3 2 1
.......3 1
........ 1
And so on. Hopefully this gets you started on a solution.
There is also different way of thinking about this. Given an NxN board, you have to make 2N moves to get from one corner to the other. N of these moves are north moves and N are east. The question is: how many different combinations of N east moves and N north moves can there be in a 2N-long string.
You are looking for Pascal's triangle. The wikipedia link even mentions your exact problem

Categories