Keep track of items in dynamic programming(similar to Knapsack problem) - python

Hello I'm trying to solve this dp problem: https://vjudge.net/problem/UVA-990
I'm able to solve the initial problem result using this code below:
I used recursion and a memo table arr to optimize the code.
s=list(map(int,input().split()))
t=s[0] #seconds allowed under water
w=s[1] #w
n=int(input()) #number of treasures
depth=[-1]
gold=[-1]
time=[-1]
for i in range(3):
q=list(map(int,input().split()))
depth.append(q[0])
gold.append(q[1])
time.append(q[0]*w*3)
arr = [[-1]*(t+1) for i in range(0,(n+1))]
def maxGold(n,T):
if n==0 or T==0:
return 0
if arr[n][T]!=-1:
return arr[n][T]
if time[n]>T:
answer=maxGold(n-1,T)
else:
answer=max(maxGold(n-1,T),gold[n]+maxGold(n-1,T-time[n]))
arr[n][T]=answer
return answer
result=maxGold(n,t)
print(result)
However I have no idea how to keep track of the chosen items.
I was thinking to store all indices of chosen treasures of the maxGold() output and print them later in a loop for instance.
One approach I had was to add a paramter to the maxGold() function and append to it the indices and return two result and the indices list from the function like the following:
def maxGold(n,T,l):
if n==0 or T==0:
return 0,l
if arr[n][T]!=-1:
return arr[n][T],l
if time[n]>T:
answer=maxGold(n-1,T,l)
else:
l2=l[:]
l2.append(n)
answer=max(maxGold(n-1,T,l)[0],gold[n]+maxGold(n-1,T-time[n],l2)[0])
arr[n][T]=answer
return answer,l
result=maxGold(n,t,[])
print(result[0])
list_of_indices=result[1]
length=len(list_of_indices)
#proceed outputs
However I ran into many tuple/integer type, subscriptable,iteratable errors. from this specific line even after trying to get a round the tuple output due to several outputs :
answer=max(maxGold(n-1,T,l)[0],gold[n]+maxGold(n-1,T-time[n],l2)[0])
And honestly I'm uncertain whether this approach is the right one.
Any hints?

Related

Inexplicable error deleting elements from a list after taking them from that same list

I am currently having an error deleting 2 elements from a list after taking them from that same list. The problem does not seem difficult, and it is not, but I getting an error that I am not able to explain.
Initially I have two list: list_h (with 30.000 elements) and list_v (with 60.000 elements). The problem here is just to iterate, choosing each iteration between list_h or list_v until both of the lists are empty. The choice between both lists is made randomly each iteration and a condition must be fulfilled: if list_h is chosen, one element is added to a final list and deleted from the list it came from and if list_v is chosen, we have to choose one pair of elements, adding them in the same way as an element to that same final list and deleted from list_v. Obviously, such a pair of elements cannot consist of the same element twice.
The whole process takes a few tens of minutes, but despite the fact that for most of the elements there is no error at all, surprisingly every time I try it, in some iterations an error occurs showing that an element has been tried to be deleted twice. In fact, I print the elements before deleting them to verify that they are indeed not the same, but the function (which follows immediately after printing the elements) receives two identical element that are neither of the two that were just printed.
Example:
def add_vertical_picture(pic1, pic2, f_s_order, pic_left):
try:
pic_left.remove(pic1)
pic_left.remove(pic2)
f_s_order.add((pic1, pic2))
except Exception as e:
print('V Error in: ', pic1.show_pic_info())
return pic_left, f_s_order
def find_nextpic_maxscore(last_pic, orientation_order_l):
best_score = 0
best_next_pic = None
pic2 = None
for i in range(len(orientation_order_l)):
score_v = get_2pictures_score(last_pic, orientation_order_l[i])
if score_v>best_score:
best_score = score_v
best_next_pic = orientation_order_l[i]
if orientation_order_l[0].orientation == 'V':
for s in [orientation_order_l[i] for i in range(len(orientation_order_l)) if orientation_order_l[i].id_num != best_next_pic.id_num]:
if s.id_num != best_next_pic.id_num:
pic2 = s
return best_next_pic, pic2
while len(Hpictures_left)>0 or len(Vpictures_left)>0:
V_prob = len(Vpictures_left)/(len(Vpictures_left)+len(Hpictures_left))
if np.random.random_sample()<V_prob: # Vertical photo
best_next_Vpic, best2_next_Vpic = find_nextpic_maxscore(list(final_slice_order)[-1], Vpictures_left)
print('Best1: ', best_next_Vpic.show_pic_info(),' -- Best2:', best2_next_Vpic.show_pic_info())
Vpictures_left, final_slice_order = add_vertical_picture(best_next_Vpic, best2_next_Vpic, final_slice_order, Vpictures_left)
And there is more! Every time I execute the program, the numbers of errors that occur changes, sometimes there are only two errors, but sometimes the number increases to 10 or more... How can I explain this?
Thanks you all in advance

Python Recursion Issue; I Can’t Change My Hard Code Into a Recursive Function

beside(picture,picture) #beside takes two pictures as arguments and prints them side by side in a 1:1 ratio.
stackn(n,picture) #stackn takes a number and a picture as arguments and prints n number of shapes in a vertical row.
show(picture) #show takes a picture as an argument and shows it on the canvas
In this case picture is the parameter heart_bb:
(n=2)# show(beside((stackn(1,heart_bb)),(stackn(2,heart_bb))))
(n=3)# show(beside((stackn(1,heart_bb)),(beside((stackn(2,heart_bb)),(stackn(4,heart_bb))))))
(n=4)# show(beside((stackn(1,heart_bb)),(beside((stackn(2,heart_bb)),(beside((stackn(4,heart_bb)),(stackn(8,heart_bb))))))))
My task is to come up with a recursive function(I’m going to call it test):
def test(n, picture):
I need this function to return the corresponding line of code shown above. For example, test(3,heart_bb) should return the line of code for n=3. Likewise, test(4,heart_bb) will return the line of code for n=4.
It has to work for any n>1, but after n=5 coding it gets really tedious.
def fractal(picture,n):
if n==1:
return(picture)
else:
return(beside((fractal(picture,(n-1))),(stackn((2**(n-1)), (picture)))))
I suppose you mainly need an idea of how you can do it and not a way to find someone that writes the code for you.
I would suggest to use a n-ary beside operation in place of your one, in such a way to simplify the code for n=2,3,4,... Since I cannot modify it I will define a new one in terms of your binary operation in this way:
def beside_pictures(pictures):
assert len(pictures) > 0
result = pictures[-1]
for tmp in pictures[:-1:-1]: # reverse order, starting from -1
result = beside(tmp, result)
return result
Now we are ready to transform your test function in a one line function:
def test(n, picture):
assert n > 0
show(beside_pictures([stackn(2**i,picture) for i in range(n)]))
UPDATE: If the requirement to have a recursive function is strict, one possible solution is the following one:
def test(n, picture):
if n == 1:
return stackn(1,picture)
return beside(test(n-1, picture), stackn(2**(n-1),picture))

How to count the output of a defined function?

I'm new to Python and trying to figure out a rather simple way to count the output of a defined function. I want to count the number of unique users who have replied to a given username by defining a function to do this.
st='#'
en=' '
task1dict={}
for t in a,b,c,d,e,f,g,h,i,j,k,l,m,n:
if t['text'][0]=='#':
print('...'),print(t['user']),print(t['text'].split(st)[-1].split(en)[0])
user=t['user']
repliedto=t['text'].split(st)[-1].split(en)[0]
task1dict.setdefault(user, set())
task1dict[user].add(repliedto)
task1dict['realDonaldTrump'].add('joeclarkphd')
This returns what is below when I enter
print(task1dict)
{'datageek88': {'fundevil', 'joeclarknet', 'joeclarkphd'},
'fundevil': {'datageek88'},
'joeclarkphd': {'datageek88'},
'realDonaldTrump': {'datageek88', 'joeclarkphd'},
'sundevil1992': {'datageek88', 'joeclarkphd'}}
I then want to print all the Twitter users who replied to a certain user for example, all the people who replied to datageek88 is done by
def print_users_who_got_replies_from(tweeter):
for z in task1dict:
if tweeter in task1dict[z]:
print(z)
This prints me what is below when I enter:
print_users_who_got_replies_from('datageek88')
fundevil
joeclarkphd
sundevil1992
realDonaldTrump
Now, I want to count the number of replies by defining a function that then prints how many people replied to a user. This function should return the answer as a number (4), but I can't seem to get that part to work, any suggestions or help? Thanks! I have tried using the len() function but can't seem to get that to work, although it might be the answer.
Rule of thumb: when you have a function that prints many things, and you think "ok now how do I interact with those values that were printed?", that's a signal that you should be appending those values to a list rather than printing them.
In this case, the most straightforward modification to the code would be
def get_users_who_got_replies_from(tweeter):
result = []
for z in task1dict:
if tweeter in task1dict[z]:
result.append(z)
return result
seq = get_users_who_got_replies_from('datageek88')
for item in seq:
print(item)
print("Number of users who got replies:", len(seq))
Bonus advanced approach: strictly speaking, you don't need a whole function just to create and return one list based on the contents of another iterable. You could do it with a list comprehension:
seq = [z for z in task1dict if 'datageek88' in task1dict[x]]
for item in seq:
print(item)
print("Number of users who got replies:", len(seq))

Really weird python error

...
def splitMunipulation(p,threshold=5000):
runs=[];i=0
while i<len(p):
l=[];i+=1
print i,p[i]
while p[i]!=press(0,1,0):
l.append(p[i]);i+=1
else:
runs.append(l)#here i points to another (0,1,0)
return runs
...
record=splitMunipulation(record)
'''
Output:
1 <__main__.press instance at 0x046690A8>
File "H:\mutate.py", line 28, in splitMunipulation
while p[i]!=press(0,1,0):
IndexError: list index out of range
pressis a class
and since print p[i] works well,why p[i] is considered out of range?
Really don't get what's going on
'''
so, a few things..
Firstly, your code is very... unpythonic. This isn't C, so you don't need to use while loops for iteration, and don't use semicolons to separate multiple commands on one line in Python. Ever. Also, the while...else format is confusing and should be avoided.
If you look at the first few 'lines' of your while loop,
while i<len(p):
l=[];i+=1
You keep i below the length of p, but you immediately increase i's value by one. As such, when i=len(p) - 1, you will make i one larger, len(p). So when you try to access p[i], you are trying to access a value that doesn't exist.
Fixing those issues, you would get:
...
def splitMunipulation(p,threshold=5000):
runs=[]
for i in p:
l=[]
print i
if i != press(0,1,0):
runs.append(i)
return runs
...
record=splitMunipulation(record)
while p[i]!=press(0,1,0):
l.append(p[i]);i+=1
The variable i gets incremented in this loop until p[i]!=press(0,1,0). Since nothing is happening to make p longer, or to test that i is not greater than the length of p, it is easy to see how the index could get out of range.
len returns the length, not the last index. If l=[1,2,3], then len(l) returns 3, but l[3] is out of range.
so you should use
while i<len(p)-1
or better yet:
for i in range(len(p)):

python, how to write an iterative function

I am quering a database for some paramaters which depend on a attribute called count! count can be incremented incase the 1st query does not return anything. Here is a sample code
sls = {(213.243, 55.556): {}, (217.193, 55.793): {}, (213.403, 55.369): {}}
for key in sls.keys:
if not sls[key]:
ra, dec = key[0], key[1]
search_from_sourcelist(sl, ra,dec)
count = 1
def search_from_sourcelist(sl, ra,dec):
dist = count/3600.0
sls[(ra,dec)] = sl.sources.area_search(Area=(ra,dec,dist))
return
Incase i run the method search_from_sourcelist, and it doesnt return anything, i would like to increment count, and do the query again. This is to be done for all keys in sls dictionary, untill all the keys have a value!!
Here is the most fundamental recursive function
def countdown(n):
if n == 0:
return "Blastoff"
else:
print "T minus %s" % n
return countdown(n-1)
You will notice that countdown returns itself with a modified argument, in this case n but -1, so if you actually followed this all the way through you would get
(-> indicates a call)
countdown(5) -> countdown(4) -> countdown(3) -> countdown(2) -> countdown(1) -> countdown(0) #stop
So now you understand what a recursive function looks like you realize you never actually return a call of your own function, thus your code is not recursive
We use recursion because we want to boil a task down to its simplest form then work from there, so a good example of this would be the mcnuggets problem. So you need to tell us what you are trying to achieve and how it can be made a smaller problem (or more importantly why.) Are you sure you cannot do this iteratively? remember you don't want to blow your stack depth because python is NOT tail recursive by standard
Recursion is useful when you find a way to reduce the initial problem to a "smaller version of itself".
The standard example is the factorial function
def fac(n):
return n * fac(n-1) if n > 1 else 1
Here you reduce the problem of calculating the factorial of n to calculating the factorial of n-1.
In your code there is no such "reduction". You just increment a value and start the same problem over again. Thus, I recommend you solve it iteratively.
I'm not sure that you need a recursive algorithm for this.
Incase i run the method search_from_sourcelist, and it doesnt return anything, i would like to increment count, and do the query again. This can be done with a while loop as follows:
for key, value in sls.iteritems():
if not value:
ra, dec = key[0], key[1]
count = 1
while not search_from_sourcelist(sls, ra, dec):
count += 1
But if you really do want to do this recursively, you can do it as follows, leave a comment and I'll write it up.
Further, you should look into your search_from_sourcelist function, as it always returns None

Categories