Fibonacci mortal rabbits with variable fecundity - python

I'm trying to modify the python code for Fibonacci mortal rabbits in order to vary the fecundity of the rabbits depending on their age.
Let's make an example.
My rabbits achieve maturity after 3 months and die after 6 months. During their 4 months of fecundity they produce a different number of offspring depending on their age. When they are 3 months old produce 2 pairs of bunnies, at 4 months produce 3 pairs of bunnies and so on till the sixth month. Each pair of bunnies is formed by a female and a male. In the end I would count the number of pairs not the number of individuals.
Fecundity values from the birth to the death:
fecundity = [0, 0, 2, 3, 3, 1]
The python code that I'm using (https://github.com/jschendel/Rosalind/blob/master/011_FIBD.py) is:
n = 12
m = 6
#n = months to run
#m = how many months the rabbits live
# Populate the initial rabbits.
Rabbits = [1]+[0]*(m-1)
# Calculate the new rabbits (bunnies), in a given month.
# Start at use range(1,n) since our initial population is 0 month old.
for month in range(1, n):
Bunnies = 0
# Get the number of Rabbits able to old enough to give birth.
for j in range(1,m):
Bunnies += Rabbits[(month-j-1)%m]
# Bunnies replace the old rabbits who died.
Rabbits[(month)%m] = Bunnies
# Total rabbits is the sum of the living rabbits.
Total_Rabbits = sum(Rabbits)
I'm not sure how to implement the variation of fecundity. Any help is appreciated!
Thank you,
Valentina

Define your fecundity array to stop when a rabbit dies :
fecundity = [0, 0, 2, 3, 3, 1]
means your rabbits die at the age of 7 months old.
After that, you just write a recursive function to calculate the number of new_borns in a specific step. I initialize the steps as 1 pair for step 0, and 0 pair for step < 0. You can of course change it to fit your case. (What I call a step is one unit of time, here the month).
Here is the function :
def new_borns(step):
if step < 0:
return 0
if step == 0:
return 1
nb_newborns = 0
# We create a loop on living pairs
for old_step in range(1, len(fecondity) +1):
nb_newborns += (fecundity[old_step -1]) * new_borns(step - old_step)
return nb_newborns
The total population of a specific step is the total of new_borns for the previous steps, still living (ie, for the length of your fecundity array).
def FIBD(step):
population = 0
for i in range(len(fecundity)):
population += new_borns(step - i)
return population
To know how many pairs you have at step 7, just call FIBD(7) The number of months the rabbit can live is the length of the fecundity array.
Of course, this recursive function is very very slow and bad. You need a caching system to avoid to calculate multiple times the same step. Here is the full file to write.
#!/usr/bin/env python
fecundity = [0, 0, 2, 3, 3, 1]
new_borns_cache = [1]
def new_borns(step):
if step < 0:
return 0
try :
return new_borns_cache[step]
except IndexError:
if step == 0:
return 1
sum = 0
for old_step in range(1, len(fecundity) +1):
sum += (fecundity[old_step -1]) * new_borns(step - old_step)
return sum
def fibd(step):
population = 0
for i in range(len(fecundity)):
population += new_borns(step - i)
return population
To use it, just import , and call fibd(7)

I came to an answer myself and I really modified the code that I posted previously. I think that now it is much simpler
import numpy as np
m = 15
n = 18
fecundity = np.array([0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 1, 2, 1, 1, 1])
Bunnies = np.array([0]*m)
Rabbits = np.array([1]+[0]*(m-1))
for month in range(0, 18):
# every month I shift the list of 1 since they're getting older
Rabbits = np.roll(Rabbits, 1)
# I set the newborns as 0
Rabbits[0] = 0
# I calculate the newborns
Bunnies = Rabbits * fecundity
# and then I assign them to the rabbits 0 month old
Rabbits[0] = sum(Bunnies)
# the sum of Rabbits is the number of final pairs of Rabbits after n months
Total_Rabbits = sum(Rabbits)
# 26 Rabbits

Related

Check if variable changes in for loop in Python

I have this code here and I'm looking for a way to check if min_score and max_score changes, and count how many times it changes. I can't seem to find a way to do it:
games = int(input())
score = list(input().split())
score = [int(x) for x in score]
for y in range(1, len(score) + 1):
min_score = (str(min(score[:y])) + " MIN")
max_score = (str(max(score[:y])) + " MAX")
print(min_score)
print(max_score)
This is a sample test case for reference:
9
10 5 20 20 4 5 2 25 1
First number is the size of the array, which in my code I never use because I make an array just from the string of numbers below ( in fact I don't even know why they give the size).
Basically I need to find how many times the max and min values change. I'm still a beginner in programming and I don't really know what to do..
you could just keep track of the lowest and highest number encountered and check if the current score is just below or above. A simple script could look like this:
scores = [10,5,20,20,4,5,2,25,1]
countChanges = 0
limitLow = float("inf")
limitHigh = -float("inf")
for s in scores:
if(s < limitLow):
countChanges += 1
limitLow = s
if(s > limitHigh):
countChanges += 1
limitHigh = s
print("current score: %3d limits: [%2d .. %2d] changes:%d" % (s, limitLow, limitHigh, countChanges))
spam = [10, 5, 20, 20, 4, 5, 2, 25, 1]
print(sum(n < min(spam[:idx]) for idx, n in enumerate(spam[1:], start=1)))
print(sum(n > max(spam[:idx]) for idx, n in enumerate(spam[1:], start=1)))
output
4
2
if you also want to account for initial value - add 1.
Looks like a hankerrank problem? They often give the length of the input to allow solutions without knowing about built-in methods like len().
Anyway,
You can initialise min and max to the first element of the array (if it exists, check the specification), or some suitably small and large values (again, check the possible values).
Then you can count the number of times min and max changes as you go.
Should be easy enough to adapt for the case that you just want to track any change, not min and max separately. It wasn't clear from your question.
scores = [10, 5, 20, 20, 4, 5, 2, 25, 1]
min_score = scores[0]
max_score = scores[0]
min_score_changes = 0
max_score_changes = 0
for score in scores:
if score < min_score:
min_score = score
min_score_changes += 1
if score > max_score:
max_score = score
max_score_changes += 1
I solved it like this after some thinking:
games = int(input())
score = list(input().split())
score = [int(x) for x in score]
min_score_list, max_score_list = [] , []
for y in range(1, len(score) + 1):
min_score = (min(score[:y]))
max_score = (max(score[:y]))
if min_score not in min_score_list:
min_score_list.append(min_score)
if max_score not in max_score_list:
max_score_list.append(max_score)
print((len(max_score_list) - 1), len(min_score_list) - 1)
I know it's not perfect code but at least I did myself :D

pick cards (fewer cards ,cost less) - performance issue

n - number of cards in hand eg : n = 4
collection - cards collection as per n eg: collection =[1,3,4,7]
d denotes total cards eg: 10 [1,2,3,4,5,6,7,8,9,10]
Card 1-cost 1 ; card 5-cost 5
Scenario : need to pick cards not in the collection list and the card cost less than (d) and maximum no of possible cards need to show
eg: sum of (2+5) <10 so we need to show (fewer cards ,cost less) accepted
eg: sum of (2+6) < 10 rejected (fewer cards ,cost more)
eg: sum of (2+5+6) < 10 rejected (more cards ,cost more,count more than d)
eg: sum of (2+8) < 10 rejected (cost more)
it working fine for small data getting performance issue:
Scenario 1:
start = time. time()
n=4
collection=[1,3,4,7]
d=10
lis=[]
list1=[]
[lis.append(x+1) for x in range(0,d)]
[lis.remove(x) for x in collection]
#print(lis)
#for L in range(0, len(lis)+1):
for subset in itertools.combinations(lis, d%n):
if sum(subset)<=d:
#print(subset)
list1.append(subset)
k = list(map(lambda x: len(x),list1))
s = list(filter (lambda x: len(x)==max(k),list1))
m = list(filter(lambda x: sum(x) == min(list(map(lambda x: sum(x),s))),s))
print(*m[0],sep='\n')
end = time. time()
print(end - start)
Result:
2 5
time 0.0
scenario 2 : n=8 collection=[1,3,4,7,20,25,50,60] d=100
Result
2
5
6
8
Time:762.9762706756592
If I understand your problem correctly, I think this does something like what you want:
def pick_cards(collection, d):
collection_set = set(collection)
# The ordered sequence of cards not in collection
pickable = (i for i in range(1, d + 1) if i not in collection_set)
# Sum of picked cards
s = 0
# Picked cards
picked = []
for pick in pickable:
# If the card does not go over the limit
if s + pick < d:
# Add card
picked.append(pick)
s += pick
else:
# Otherwise finish
break
return picked
# Examples
print(pick_cards([1, 3, 4, 7], 10))
# [2, 5]
print(pick_cards([1, 3, 4, 7, 20, 25, 50, 60], 100))
# [2, 5, 6, 8, 9, 10, 11, 12, 13, 14]

How can I improve the time complexity of this algorithm for finding the max stock price?

I am currently passing the sample tests and 2 of the other 10 cases so 4 out of 12. However, I don't make it through all of the data. I am getting a Terminated due to timeout error which means that my solution isn't fast enough.
def stockmax(prices):
total = 0
for index, price in enumerate(prices):
if index < len(prices) - 1:
section = max(prices[index+1:])
if prices[index] < section:
total += section - prices[index]
return total
I tried to do everything in only one loop. But how exactly can speed this type of question up. I also tried to cut some lines of the code but it is equally as inefficient.
def stockmax(prices):
total = 0
for index, price in enumerate(prices):
if index < len(prices) - 1 and prices[index] < max(prices[index+1:]):
total += max(prices[index+1:]) - prices[index]
return total
Though it passes the same amount of test cases.
I also tried to use heapq but it passes the same test cases and fails due to time.
def stockmax(prices):
total = 0
for index, price in enumerate(prices):
if index < len(prices) - 1:
section = heapq.nlargest(1,prices[index+1:])[0]
if prices[index] < section:
total += section - prices[index]
return total
https://www.hackerrank.com/challenges/stockmax/topics/dynamic-programming-basics
for details on the problem.
https://hr-testcases-us-east-1.s3.amazonaws.com/330/input09.txt?AWSAccessKeyId=AKIAJ4WZFDFQTZRGO3QA&Expires=1538902058&Signature=3%2FnfZzPO8XKRNyGG0Yu9qJIptgk%3D&response-content-type=text%2Fplain
for a link of some test cases but will expire after a while.
Problem
Your algorithms have become so good at predicting the market that you now know what the share price of Wooden Orange Toothpicks Inc. (WOT) will be for the next number of days.
Each day, you can either buy one share of WOT, sell any number of shares of WOT that you own, or not make any transaction at all. What is the maximum profit you can obtain with an optimum trading strategy?
For example, if you know that prices for the next two days are prices = [1,2], you should buy one share day one, and sell it day two for a profit of 1. If they are instead prices = [2,1], no profit can be made so you don't buy or sell stock those days.
Function Description
Complete the stockmax function in the editor below. It must return an integer that represents the maximum profit achievable.
stockmax has the following parameter(s):
prices: an array of integers that represent predicted daily stock prices
Input Format
The first line contains the number of test cases t.
Each of the next t pairs of lines contain:
The first line contains an integer n, the number of predicted prices for WOT.
The next line contains n space-separated integers prices [i], each a predicted stock price for day i.
Constraints
1 <= t <= 10
1 <= n <= 50000
1 <= prices [i] <= 100000
Output Format
Output lines, each containing the maximum profit which can be obtained for the corresponding test case.
Sample Input
3
3
5 3 2
3
1 2 100
4
1 3 1 2
Sample Output
0
197
3
Explanation
For the first case, you cannot obtain any profit because the share price never rises.
For the second case, you can buy one share on the first two days and sell both of them on the third day.
For the third case, you can buy one share on day 1, sell one on day 2, buy one share on day 3, and sell one share on day 4.
Clearly, for any price we can buy, we would want to sell it at the highest price. Fortunately, we are given that highest price. So, iterating backwards, we know the highest future price seen at any point we visit in our travel "back in time."
Python code:
def stockmax(prices):
n = len(prices)
highest = prices[n - 1]
m = [0] * n
# Travel back in time,
# deciding whether to buy or not
for i in xrange(n - 2, -1, -1):
# The most profit buying stock at this point
# is what we may have made the next day
# (which is stored in m[i + 1])
# and what we could make if we bought today
m[i] = m[i + 1] + max(
# buy
highest - prices[i],
# don't buy
0
)
# Update the highest "future price"
highest = max(highest, prices[i])
return m[0]
If you can use Numpy, then something similar to the below should be rather quick (I believe it's the same idea as the answer from #גלעד ברקן).
import numpy as np
with open('.../input09.txt') as fd:
numtests = int(fd.readline().strip())
counter = 0
numvals = 0
vals = None
steps = None
for line in fd:
if (counter % 2 == 0) :
numvals = int(line.strip())
else:
vals = np.fromstring(line, dtype=int, sep=' ', count=numvals)
assert len(vals) == numvals
cum_max = np.maximum.accumulate(vals[::-1])
np.roll(cum_max, -1)
cum_max[len(cum_max) - 1] = 0
delta = (cum_max - vals)
print('#', counter + 1, 'sum:', np.sum(delta * (delta > 0)))
counter += 1
it runs almost instantly on tests from the input09.txt.
Here is my solution written in ruby.
The solution obtained perfect score.
def solution(a)
gain = 0
i = a.count - 1
min = false
mi = false
while i > 0
s = a.delete_at(i)
unless min
mi = a.index(a.min)
min = a[mi]
end
g = s - min
gain = g if g > gain
i -= 1
min = false if i == mi
end
gain
end

List indexes - If too big go back to the beginning of the list

So, maybe this question will sound very beginnerish, but I just don't know how I should begin with this example:
So the example is:
I have a list for example 13 items long (1,2,3,4...13)
There's a given number, let's say 6
The program needs to show me in a list, in what order are the numbers going to fall out. If the second number is 6, it means every time the sixth item is the next whcih is going to fall out. But my problem is that how could I tell python that if the index number goes up too high, it should start counting again from the beggining?
This is what I made myself so far
x = int(input("Number of items (numbers): "))
y = int(input("Fall-out number: "))
#n = 1
#id = 0
numbers = [n for n in range(x+1)]
fallsout = []
numbers.remove(30)
for i in numbers:
if i % y == 0:
fallsout.append(i)
print (numbers)
print (fallsout)
Here's an example what should be in the input and output:
Input:
x = 13
y = 6
Output: 6 12 5 13 8 3 1 11 2 7 4 10 9
Okay, looks like you want to copy every 6th element from numbers into fallout and then remove the element from numbers, and continue on in a cyclic fashion until numbers is empty.
import copy
x = int(input("Number of items (numbers): "))
y = int(input("Fall-out number: "))
# list should start from 1 as by the example
numbers = [n for n in range(1,x+1)]
# deep copy to preserve original list
numbers_copy = copy.deepcopy(numbers)
fallsout = []
count = y
while len(numbers_copy)!=0:
fallsout.append(numbers_copy[count-1])
# remove element
del numbers_copy[count-1]
# handle starting edge
if count == 0:
count = 1
# handle last edge
if numbers_copy != []:
count = (count+y-1)%len(numbers_copy)
print numbers
print fallsout
Output is
Number of items (numbers): 13
Fall-out number: 6
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
[6, 12, 5, 13, 8, 3, 1, 11, 2, 7, 4, 10, 9]
Explanation:
Suppose I have a array numbers = [1,2,3,4,5,6] of length=6, and I am using an counter "count" to iterate through the list. So that,
numbers[count] = 2 (when count=1)
Then to look at the next element, I would use numbers[count+1].
To jump back to the starting of the list, we use modulus operation,
count = (count+number_of_steps)%len(numbers)
eg, at index=4 and to jump 3 steps, next index would be (4+3)%6 = 1
Now we have to copy every yth element from the list,so we use,
fallsout.append(numbers_copy[count-1]) # count-1 as we are counting from 0
Then we remove that number from the list,
del numbers_copy[count-1]
Then we jump forward count by y steps by modulus as discussed above,
count = (count+y-1)%len(numbers_copy) # again -1 as we count from 0
The length of numbers needs to be calculated again as the list could change due to deleting of elements.

subtract n values from input python

I haven't found anything even relevant to my question, so i may be asking it wrong.
I am working on an exercise where I am given sequential values starting at 1 and going to n, but not in order. I must find a missing value from the list.
My method is to add the full 1 => n value in a for loop but I can't figure out how to add n - 1 non-sequential values each as its own line of input in order to subtract it from the full value to get the missing one.
I have been searching modifications to for loops or just how to add n inputs of non-sequential numbers. If I am simply asking the wrong question, I am happy to do my own research if someone could point me in the right direction.
total = 0
for i in range (1 , (int(input())) + 1):
total += i
print(total)
for s in **?????(int(input()))**:
total -= s
print(total)
sample input:
5
3
2
5
1
expected output: 4
To fill in the approach you're using in your example code:
total = 0
n = int(input("How long is the sequence? "))
for i in range(1, n+1):
total += i
for i in range(1, n):
total -= int(input("Enter value {}: ".format(i)))
print("Missing value is: " + str(total))
That first for loop is unnecessary though. First of all, your loop is equivalent to the sum function:
total = sum(range(1,n+1))
But you can do away with any iteration altogether by using the formula:
total = int(n*(n+1)/2) # division causes float output so you have to convert back to an int
I don't know if you are supposed to create the initial data (with the missing item), so I added some lines to generate this sequence:
import random
n = 12 # or n = int(input('Enter n: ')) to get user input
# create a shuffled numeric sequence with one missing value
data = list(range(1,n+1))
data.remove(random.randrange(1,n+1))
random.shuffle(data)
print(data)
# create the corresponding reference sequence (without missing value)
data2 = list(range(1,n+1))
# find missing data with your algorithm
print("Missing value =", sum(data2)-sum(data))
Here is the output:
[12, 4, 11, 5, 2, 7, 1, 6, 8, 9, 10]
Missing value = 3

Categories

Resources