Ulam Spiral (for diagonal numbers) writing program python - python

I am writing a code the represent the Ulam Spiral Diagonal Numbers and this is the code I typed myself
t = 1
i = 2
H = [1]
while i < 25691 :
for n in range(4):
t += i
H.append(t)
i += 2
print(H)
The number "25691" in the code is the side lenght of the spiral.If it was 7 then the spiral would contain 49 numbers etc.
Here H will give you the all numbers in diagonal. But I wonder is there a much faster way to do this.
For example if I increase the side lenght large amount it really takes forever to calculate the next H.
Code Example:
t = 1
i = 2
H = [1]
for j in range(25000,26000):
while i < j :
for n in range(4):
t += i
H.append(t)
i += 2
For example my computer cannot calculate it so, is there a faster way to do this ?

You dont need to calculate the intermediate values:
Diagonal, horizontal, and vertical lines in the number spiral correspond to polynomials of the form
where b and c are integer constants.
wikipedia
You can find b and c by solving a linear system of equations for two numbers.
17 16 15 14 13
18 5 4 3 12 ..
19 6 1 2 11 28
20 7 8 9 10 27
21 22 23 24 25 26
Eg for the line 1,2,11,28 etc:
f(0) = 4*0*0+0*b+c = 1 => c = 1
f(1) = 4*1*1+1*b+1 = 2 => 5+b = 2 => b = -3
f(2) = 4*2*2+2*(-3)+1 = 11
f(3) = 4*3*3+3*(-3)+1 = 28

Related

How to structure nested for loops?

I am new to Python. I have been studying for loops but I can't seem to get my head around NESTED for loops. I am doing a problem which requires knowledge of nested for loops, which I do not know how to do!
Problem:
Write a for loop that produces the following output:
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
0
2
4
6
8
10
12
14
16
18
0
3
6
9
12
15
18
0
4
8
12
16
Caveat: You can only use up to two for loops
My Code:
c = 0
for i in range(1, 5):
for j in range(10):
print(i * c)
c = c + 1
Any help will be appreciated. I just cannot get my head around nested for loops. It would be great if anybody could guide me.
One could do it like:
for step in range(1, 5):
for i in range(0, 20, step):
print(i)
Using list comprehension:
print(*[i for step in range(1, 5) for i in range(0, 20, step)], sep="\n")
You don't need the c variable, you can multiply by j.
The inner loop shouldn't go up to 10 every time. Notice that as the multiplyer increases, the number of iterations goes down -- each time stops before 20. So you need to divide 20 by i to get the number of iterations.
for i in range(1, 5):
for j in range(20//i):
print(i * j)

An algorithm for efficiently replacing an array elements with groups

There are N elements, each element has its own cost. And there are M groups. Each group includes several indices of elements from the array and has its own cost.
input for example
6
100 5
200 5
300 5
400 5
500 5
600 3
2
4 6
100 200 300 700
3 5
300 400 500
The first number N is the number of elements. The next N lines contain the index and cost of a particular item. Then comes the number M (number of groups). After it comes 2*M lines . These lines contain the number of elements in the group, the cost of the group itself, and the indices of the elements.
I want to find the minimum cost for which can purchase all N items.
In the example, it is most advantageous to take both groups and purchase an element with the number 600 separately. The answer is 14. (6+5+3)
Here is my solution
from queue import PriorityQueue
N = int(input())
dct = {}
groups = PriorityQueue()
for i in range(N):
a,c = [int(j) for j in input().split()]
dct[a] = c
M = int(input())
for i in range(M):
k,c = [int(j) for j in input().split()]
s = 0
tmp = []
for j in input().split():
j_=int(j)
if j_ in dct:
s+=dct[j_]
tmp.append(j_)
d = c-s
if d<0:
groups.put([d, c, tmp])
s = 0
while not groups.empty():
#print(dct)
#for i in groups.queue:
# print(i)
g = groups.get()
if g[0]>0:
break
#print('G',g)
#print('-------')
for i in g[2]:
if i in dct:
del(dct[i])
s += g[1]
groups_ = PriorityQueue()
for i in range(len(groups.queue)):
g_ = groups.get()
s_ = 0
tmp_ = []
for i in g_[2]:
if i in dct:
s_+=dct[i]
tmp_.append(i)
d = g_[1]-s_
groups_.put([d, g_[1], tmp_])
groups = groups_
for i in dct:
s+=dct[i]
print(s)
But it is not completely true.
For example, for such a test, it gives an answer of 162. But the correct answer is 160. It is most beneficial to take only the first and second groups and take an element with index 0 separately.
20
0 24
1 32
2 33
3 57
4 57
5 50
6 50
7 41
8 2
9 73
10 81
11 73
12 55
13 3
14 54
15 43
16 98
17 8
18 41
19 97
5
17 61
17 9 11 15 1 13 14 7 20 2 3 16 12 5 8 4 6
13 75
20 15 5 9 10 11 7 8 18 2 4 19 16
10 96
3 9 4 18 11 6 8 5 2 14
9 92
18 1 6 9 19 8 4 16 10
19 77
14 17 18 3 2 4 7 6 8 9 10 20 13 12 15 19 1 16 5
I also tried brute-force search, but such a solution would be too slow
from itertools import combinations
N = int(input())
dct = {}
s = 0
for i in range(N):
a,c = [int(j) for j in input().split()]
dct[a] = c
s += c
m = s
M = int(input())
groups = []
for i in range(M):
k,c = [int(j) for j in input().split()]
s = 0
tmp = []
for j in input().split():
j_=int(j)
if j_ in dct:
s+=dct[j_]
tmp.append(j_)
groups.append( [c, tmp] )
for u in range(1,M+1):
for i in list(combinations(groups, u)):
s = 0
tmp = dct.copy()
for j in i:
s += j[0]
for t in j[1]:
if t in tmp:
del(tmp[t])
for j in tmp:
s += tmp[j]
#print(i,s)
if s < m:
m = s
print(m)
I think that this problem is solved with the help of dynamic programming. Perhaps this is some variation of the typical Knapsack problem. Tell me which algorithm is better to use.
The so-called set cover problem(which is NP-Hard) seems like a special case of your problem. Therefore, I am afraid there is no efficient algorithm that solves it.
As already stated, this is a hard problem for which no "efficient" algorithm exists.
You can approach this as a graph problem, where the nodes of the graph are all possible combinations of groups (where each element on its own is also a group). Two nodes u and v are connected with a directed edge when there is a group g such that the union of the keys in u and in g, corresponds to the set of keys in v.
Then perform a Dijkstra search in this graph, starting from the node that represents the state where no groups are selected at all (cost 0, no keys). This search will minimise the cost, and you can use the extra optimisation that a group g is never considered twice in the same path. As soon as a state (node) is visited that covers all the keys, you can exit the algorithm -- typical for the Dijkstra algorithm -- as this represents the minimal cost to cover all the keys.
Such an algorithm is still quite costly, as at each addition of an edge to a path, a union of keys must be calculated. And,... quite some memory is needed to keep all states in the heap.
Here is a potential implementation:
from collections import namedtuple
import heapq
# Some named tuple types, to make the code more readable
Group = namedtuple("Group", "cost numtodo keys")
Node = namedtuple("Node", "cost numtodo keys nextgroupid")
def collectinput():
inputNumbers = lambda: [int(j) for j in input().split()]
groups = []
keys = []
N, = inputNumbers()
for i in range(N):
key, cost = inputNumbers()
keys.append(key)
# Consider these atomic keys also as groups (with one key)
# The middle element of this tuple may seem superficial, but it improves sorting
groups.append(Group(cost, N-1, [key]))
keys = set(keys)
M, = inputNumbers()
for i in range(M):
cost = inputNumbers()[-1]
groupkeys = [key for key in inputNumbers() if key in keys]
groups.append(Group(cost, N-len(groupkeys), groupkeys))
return keys, groups
def solve(keys, groups):
N = len(keys)
groups.sort() # sort by cost, if equal, by number of keys left
# The starting node of the graph search
heap = [Node(0, N, [], 0)]
while len(heap):
node = heapq.heappop(heap)
if node.numtodo == 0:
return node.cost
for i in range(node.nextgroupid, len(groups)):
group = groups[i]
unionkeys = list(set(node.keys + group.keys))
if len(unionkeys) > len(node.keys):
heapq.heappush(heap, Node(node.cost + group.cost, N-len(unionkeys), unionkeys, i+1))
# Main
keys, groups = collectinput()
cost = solve(keys, groups)
print("solution: {}".format(cost))
This outputs 160 for the second problem you posted.

Printing reverse Sum of numbers from 1 to n

I am learning python and I am really struggling to figure out how to write this code where I get an input a that is bigger than 1 and the output should look like this:
Sum from 1 to a
Sum from 2 to a
Sum from 3 to a
.....
a
E.g. for 5, the output should be:
15
14
12
9
5
This is what I have so far
a=int(input())
for t in range(a):
b=a*(a+1)/2
b=b-t
print(a+t)
I cant seem to figure out how to subtract it from reverse and how to print each results in the process
The following will work:
a = int(input())
# s = sum(range(1, a+1))
s = a * (a+1) // 2
for t in range(1, a+1):
print(s)
s -= t
Produces for a = 5:
15
14
12
9
5
Instead of only subtracting the counter t, you need to subtract the sum of 1 ... t.
Otherwise your code does not need to be changed, I just added the forcing to int.
a = int(input())
for t in range(a):
b=a*(a+1)//2
c=t*(t+1)//2
b=b-c
print(b)
Output:
15
14
12
9
5

How do you triangulate a number in python?

I have to do these for school and I don't know how to.
Write a function print_triangular_numbers(n) that prints out the first n triangular numbers (n is an input). A call to print_triangular_numbers(5) would produce the following output:
n result
1 1
2 3
3 6
4 10
5 15
A triangular number can be expressed as
n(n+1)/2
Thus, you need to build a simple loop, starting at 1 and going through your passed parameter:
def print_triangular_numbers(n):
for x in range(1,n+1):
print x, x * (x + 1) / 2
The for loop starts at 1 and goes through n+1 because range is not inclusive of the end point.
This outputs:
1 1
2 3
3 6
4 10
5 15

Pascal's triangle code

I am having trouble getting this python code to work right. it is a code to display pascal's triangle using binomials. I do not know what is wrong. The code looks like this
from math import factorial
def binomial (n,k):
if k==0:
return 1
else:
return int((factorial(n)//factorial(k))*factorial(n-k))
def pascals_triangle(rows):
rows=20
for n in range (0,rows):
for k in range (0,n+1):
print(binomial(n,k))
print '\n'
This is what it keeps printing
1
1 1
1
2
1
1
12
3
1
1
144
24
4
1
1
2880
360
40
5
1
1
86400
8640
720
60
6
1
1
3628800
302400
20160
1260
and on and on. any help would be welcomed.!!
from math import factorial
def binomial (n,k):
if k==0:
return 1
else:
return int((factorial(n)//factorial(k))*factorial(n-k))
def pascals_triangle(rows):
for n in range (rows):
l = [binomial(n, k) for k in range (0,n+1)]
print l
pascals_triangle(5)
output:
[1]
[1, 1]
[1, 2, 1]
[1, 12, 3, 1]
[1, 144, 24, 4, 1]
there are many wrong things.
The first one is the way you compute the values : if building a pascal triangle, you want to use the previous line to compute the current one, and not use the binomial computation (which is expensive due to the number of multiplications).
then by default, print appends a "\n"
Correct implementation:
def print_line(x):
print (" ".join(map(str,x)))
def pascals_triangle(rows):
cur_line=[1,1]
for x in range (2,rows):
new_line=[1]
for n in range (0,len(cur_line)-1):
new_line.append(cur_line[n]+cur_line[n+1])
new_line.append(1)
print_line (new_line)
cur_line=new_line
this provides the following output
$ python pascal.py
1 2 1
1 3 3 1
1 4 6 4 1
1 5 10 10 5 1
1 6 15 20 15 6 1
1 7 21 35 35 21 7 1
1 8 28 56 70 56 28 8 1
1 9 36 84 126 126 84 36 9 1
Your binomial function had a small bracketing mistake in it, which was giving you incorrect output:
from math import factorial
def binomial(n, k):
if k==0:
return 1
else:
return int((factorial(n)/(factorial(k)*factorial(n-k))))
def pascals_triangle(rows, max_width):
for n in range (0,rows):
indent = (rows - n - 1) * max_width
print(' ' * indent, end='')
for k in range(0, n+1):
print("{:^{w}}".format(binomial(n, k), w = max_width*2), end='')
print()
pascals_triangle(7, 2)
With the addition of a padding parameter, the output can be made to look like this:
1
1 1
1 2 1
1 3 3 1
1 4 6 4 1
1 5 10 10 5 1
1 6 15 20 15 6 1

Categories