I'm writing a networking app in Python that receives numbered messages from a server. The messages have sequence numbers in the range 1..N and may come out of order. I want to track the latest message received conditioned on there being no gaps in the messages so far.
So for instance,
if the messages were 1,3,2 I would mark 3 as the latest ungapped message received.
If the messages were 1,2,5,4 I would mark 2 as the latest ungapped message received since I haven't yet received 3.
Once 3 comes in, I would mark 5 as the latest message received.
What's the most efficient way to do this? Is there some data structure or programming idiom that implements an algorithm to solve this problem?
I looked around a bit and didn't find a great answer immediately.
Here's a stab I took at doing this via a small blocking class. This could technically be O(N) for a single handle_new_index, but the average time for the handle_new_index operations should still be guaranteed to be constant.
I don't think time complexity will get much better since you have to do an insert on some kind of data structure no matter what you do.
With billions of requests and a really wide spread the non_contiguous set can have a moderate memory footprint.
import random
class gapHandler:
def __init__(self):
self.greatest = 0
self.non_contiguous = set()
def handle_new_index(self, message_index):
"""
Called when a new numbered request is sent. Updates the current
index representing the greatest contiguous request.
"""
self.non_contiguous.add(message_index)
if message_index == self.greatest + 1:
self._update_greatest()
def _update_greatest(self):
done_updating = False
while done_updating is False:
next_index = self.greatest + 1
if next_index in self.non_contiguous:
self.greatest = next_index
self.non_contiguous.remove(next_index)
else:
done_updating = True
def demo_gap_handler():
""" Runs the gapHandler class through a mock trial. """
gh = gapHandler()
for block_id in range(20000):
start = block_id*500 + 1
end = (block_id + 1)*500 + 1
indices = [x for x in range(start, end)]
random.shuffle(indices)
while indices:
new_index = indices.pop()
gh.handle_new_index(new_index)
if new_index % 50 == 0:
print(gh.greatest)
if __name__ == "__main__":
demo_gap_handler()
Here's some basic tests:
import unittest
import gaps
class testGaps(unittest.TestCase):
def test_update_greatest(self):
gh = gaps.gapHandler()
gh.non_contiguous = set((2, 3, 4, 6))
gh._update_greatest()
self.assertEqual(gh.greatest, 0)
gh.greatest = 1
gh._update_greatest()
self.assertEqual(gh.greatest, 4)
def test_handle_new_index(self):
gh = gaps.gapHandler()
gh.non_contiguous = set((2, 3, 4, 6, 2000))
gh.handle_new_index(7)
self.assertEqual(gh.greatest, 0)
gh.handle_new_index(1)
self.assertEqual(gh.greatest, 4)
gh.handle_new_index(5)
self.assertEqual(gh.greatest, 7)
if __name__ == "__main__":
unittest.main()
Related
I am iterating through very large file size [mesh]. Since the iteration is independent, I would like to split my mesh into smaller sizes and run them all at the same time in order to lower computation time. Below is a sample code. For example, if mesh is of length=50000, I would like to divide the mesh into 100 and run fun for each mesh/100 at the same time.
import numpy as np
def fnc(data, mesh):
d = []
for i, dummy_val in enumerate(mesh):
d.append(np.sqrt((data[:, 0]-mesh[i, 0])**2.0 + (data[:, 1]-mesh[i, 1])**2.0))
return d
interpolate = fnc(mydata, mymesh)
I would like to know to achieve this using multiprocessing or multithreading as I'm unable to reconcile it with the execution of my loop.
This will give you the general idea. I couldn't test this since I do not have your data. The default constructor for ProcessPoolExecutor will use the number of processors on your computer. But since that determines the level of multiprocessing you can have, it will probably be more efficient to set the N_CHUNKS parameter to the number of simultaneous processes you can support. That is, if you have a processing pool size of 6, then it is better to just divide your array into 6 large chunks and have 6 processes do the work rather than breaking it up into smaller pieces where processes will have to wait to run. So you should probably specify a specific max_workers number to the ProcessPoolExecutor not greater than the number of processors you have and set N_CHUNKS to the same value.
from concurrent.futures import ProcessPoolExecutor, as_completed
import numpy as np
def fnc(data, mesh):
d = []
for i, dummy_val in enumerate(mesh):
d.append(np.sqrt((data[:, 0]-mesh[i, 0])**2.0 + (data[:, 1]-mesh[i, 1])**2.0))
return d
def main(data, mesh):
#N_CHUNKS = 100
N_CHUNKS = 6 # assuming you have 6 processors; see max_workers parameter
n = len(mesh)
assert n != 0
if n <= N_CHUNKS:
N_CHUNKS = 1
chunk_size = n
last_chunk_size = n
else:
chunk_size = n // N_CHUNKS
last_chunk_size = n - chunk_size * (N_CHUNKS - 1)
with ProcessPoolExcutor(max_workers=N_CHUNKS) as executor: # assuming you have 6 processors
the_futures = {}
start = 0
for i in range(N_CHUNKS - 1):
future = executor.submit(fnc, data, mesh[start:start+chunk_size]) # pass slice
the_futures[future] = (start, start+chunk_size) # map future to request parameters
start += chunk_size
if last_chunk_size:
future = executor.submit(fnc, data, mesh[start:n]) # pass slice
the_futures[future] = (start, start+n)
for future in as_completed(the_futures):
(start, end) = the_futures[future] # the original range
d = future.result() # do something with the results
if __name__ == '__main__':
# the call to main must be done in a block governed by if __name__ == '__main__' or you will get into a recursive
# loop where each subprocess calls main again
main(data, mesh)
I am attempting to create Pool() objects, so that I can break down large arrays. Though, each time after the first I run through the below code, the map is never run. Only the first pass seems to enter the function, though the arguments are the same size, even when running it using the EXACT same arguments - only the first
job.map(...)
appears to run. Below is the source of my pain (not all the code in the file):
def iterCount():
#m is not in shared memory, as intended.
global m
m = m + 1
return m
def thread_search(pair):
divisor_lower = pair[0]
divisor_upper = pair[1]
for i in range(divisor_lower, divisor_upper,window_size):
current_section = np.array(x[i: i + window_size])
for row in current_section:
if (row[2].startswith('NP') ) and checkPep(row[0]): #checkPep is a simple unique-in-array checking function.
#shared_list is a multiprocessing.Manager list.
shared_list.append(row[[0,1,2]])
m = iterCount()
if not m%1000000:
print(f'Encountered m = {m}', flush = True)
def poolMap(pairs, group):
job = Pool(3)
print(f'Pool Created')
print(len(pairs))
job.map(thread_search,pairs)
print('Pool Closed')
job.close()
if __name__ == '__main__':
for group in [1,2,3]: #Example times to be run...
x = None
lower_bound = int((group - 1)*group_step)
upper_bound = int(group*group_step)
x = list(csv.reader(open(pa_table_name,"rt", encoding = "utf-8"), delimiter = "\t"))[lower_bound:upper_bound]
print(len(x))
divisor_pairs = [ [int(lower_bound + (i - 1)*chunk_size) , int(lower_bound + i*chunk_size)] for i in range(1,6143) ]
poolMap(divisor_pairs, group)
The output of this function is:
Program started: 03/09/19, 12:41:25 (Machine Time)
11008256 - Length of the file read in (in the group)
Pool Created
6142 - len(pairs)
Encountered m = 1000000
Encountered m = 1000000
Encountered m = 1000000
Encountered m = 2000000
Encountered m = 2000000
Encountered m = 2000000
Encountered m = 3000000
Encountered m = 3000000
Encountered m = 3000000 (Total size is ~ 9 million per set)
Pool Closed
11008256 (this is the number of lines read, correct value)
Pool Created
6142 (Number of pairs is correct, though map appears to never run...)
Pool Closed
11008256
Pool Created
6142
Pool Closed
At this point, the shared_list is saved, and only the first threads results appear to be present.
I'm really at a loss to what is happening here, and I've tried to find bugs (?) or similar instances of any of this.
Ubuntu 18.04
Python 3.6
My problem is as follows:
having file with list of intervals:
1 5
2 8
9 12
20 30
And a range of
0 200
I would like to do such an intersection that will report the positions [start end] between my intervals inside the given range.
For example:
8 9
12 20
30 200
Beside any ideas how to bite this, would be also nice to read some thoughts on optimization, since as always the input files are going to be huge.
this solution works as long the intervals are ordered by the start point and does not require to create a list as big as the total range.
code
with open("0.txt") as f:
t=[x.rstrip("\n").split("\t") for x in f.readlines()]
intervals=[(int(x[0]),int(x[1])) for x in t]
def find_ints(intervals, mn, mx):
next_start = mn
for x in intervals:
if next_start < x[0]:
yield next_start,x[0]
next_start = x[1]
elif next_start < x[1]:
next_start = x[1]
if next_start < mx:
yield next_start, mx
print list(find_ints(intervals, 0, 200))
output:
(in the case of the example you gave)
[(0, 1), (8, 9), (12, 20), (30, 200)]
Rough algorithm:
create an array of booleans, all set to false seen = [False]*200
Iterate over the input file, for each line start end set seen[start] .. seen[end] to be True
Once done, then you can trivially walk the array to find the unused intervals.
In terms of optimisations, if the list of input ranges is sorted on start number, then you can track the highest seen number and use that to filter ranges as they are processed -
e.g. something like
for (start,end) in input:
if end<=lowest_unseen:
next
if start<lowest_unseen:
start=lowest_unseen
...
which (ignoring the cost of the original sort) should make the whole thing O(n) - you go through the array once to tag seen/unseen and once to output unseens.
Seems I'm feeling nice. Here is the (unoptimised) code, assuming your input file is called input
seen = [False]*200
file = open('input','r')
rows = file.readlines()
for row in rows:
(start,end) = row.split(' ')
print "%s %s" % (start,end)
for x in range( int(start)-1, int(end)-1 ):
seen[x] = True
print seen[0:10]
in_unseen_block=False
start=1
for x in range(1,200):
val=seen[x-1]
if val and not in_unseen_block:
continue
if not val and in_unseen_block:
continue
# Must be at a change point.
if val:
# we have reached the end of the block
print "%s %s" % (start,x)
in_unseen_block = False
else:
# start of new block
start = x
in_unseen_block = True
# Handle end block
if in_unseen_block:
print "%s %s" % (start, 200)
I'm leaving the optimizations as an exercise for the reader.
If you make a note every time that one of your input intervals either opens or closes, you can do what you want by putting together the keys of opens and closes, sort into an ordered set, and you'll be able to essentially think, "okay, let's say that each adjacent pair of numbers forms an interval. Then I can focus all of my logic on these intervals as discrete chunks."
myRange = range(201)
intervals = [(1,5), (2,8), (9,12), (20,30)]
opens = {}
closes = {}
def open(index):
if index not in opens:
opens[index] = 0
opens[index] += 1
def close(index):
if index not in closes:
closes[index] = 0
closes[index] += 1
for start, end in intervals:
if end > start: # Making sure to exclude empty intervals, which can be problematic later
open(start)
close(end)
# Sort all the interval-endpoints that we really need to look at
oset = {0:None, 200:None}
for k in opens.keys():
oset[k] = None
for k in closes.keys():
oset[k] = None
relevant_indices = sorted(oset.keys())
# Find the clear ranges
state = 0
results = []
for i in range(len(relevant_indices) - 1):
start = relevant_indices[i]
end = relevant_indices[i+1]
start_state = state
if start in opens:
start_state += opens[start]
if start in closes:
start_state -= closes[start]
end_state = start_state
if end in opens:
end_state += opens[end]
if end in closes:
end_state -= closes[end]
state = end_state
if start_state == 0:
result_start = start
result_end = end
results.append((result_start, result_end))
for start, end in results:
print(str(start) + " " + str(end))
This outputs:
0 1
8 9
12 20
30 200
The intervals don't need to be sorted.
This question seems to be a duplicate of Merging intervals in Python.
If I understood well the problem, you have a list of intervals (1 5; 2 8; 9 12; 20 30) and a range (0 200), and you want to get the positions outside your intervals, but inside given range. Right?
There's a Python library that can help you on that: python-intervals (also available from PyPI using pip). Disclaimer: I'm the maintainer of that library.
Assuming you import this library as follows:
import intervals as I
It's quite easy to get your answer. Basically, you first want to create a disjunction of intervals based on the ones you provide:
inters = I.closed(1, 5) | I.closed(2, 8) | I.closed(9, 12) | I.closed(20, 30)
Then you compute the complement of these intervals, to get everything that is "outside":
compl = ~inters
Then you create the union with [0, 200], as you want to restrict the points to that interval:
print(compl & I.closed(0, 200))
This results in:
[0,1) | (8,9) | (12,20) | (30,200]
I am trying out the PyBrains maze example
my setup is:
envmatrix = [[...]]
env = Maze(envmatrix, (1, 8))
task = MDPMazeTask(env)
table = ActionValueTable(states_nr, actions_nr)
table.initialize(0.)
learner = Q()
agent = LearningAgent(table, learner)
experiment = Experiment(task, agent)
for i in range(1000):
experiment.doInteractions(N)
agent.learn()
agent.reset()
Now, I am not confident in the results that I am getting
The bottom-right corner (1, 8) is the absorbing state
I have put an additional punishment state (1, 7) in mdp.py:
def getReward(self):
""" compute and return the current reward (i.e. corresponding to the last action performed) """
if self.env.goal == self.env.perseus:
self.env.reset()
reward = 1
elif self.env.perseus == (1,7):
reward = -1000
else:
reward = 0
return reward
Now, I do not understand how, after 1000 runs and 200 interaction during every run, agent thinks that my punishment state is a good state (you can see the square is white)
I would like to see the values for every state and policy after the final run. How do I do that? I have found that this line table.params.reshape(81,4).max(1).reshape(9,9) returns some values, but I am not sure whether those correspond to values of the value function
Now I added another constraint - made the agent to always start from the same position: (1, 1) by adding self.initPos = [(1, 1)] in maze.py and now I get this behaviour after 1000 runs with each run having 200 interactions:
Which kind of makes sense now - the robot tries to go around the wall from another side, avoiding the state (1, 7)
So, I was getting weird results because the agent used to start from random positions, which also included the punishing state
EDIT:
Another point is that if it is desirable to spawn the agent randomly, then make sure it is not spawned in the punishable state
def _freePos(self):
""" produce a list of the free positions. """
res = []
for i, row in enumerate(self.mazeTable):
for j, p in enumerate(row):
if p == False:
if self.punishing_states != None:
if (i, j) not in self.punishing_states:
res.append((i, j))
else:
res.append((i, j))
return res
Also, seems then that table.params.reshape(81,4).max(1).reshape(9,9) returns the value for every state from the value function
This is the problem I am trying to solve:
B: The Foxen's Treasure
There are N (1 ≤ N ≤ 4) Foxen guarding a certain valuable treasure,
which you'd love to get your hands on. The problem is, the Foxen
certainly aren't about to allow that - at least, not while they're
awake.
Fortunately, through careful observation, you've seen that each Fox
has a regular sleep cycle. In particular, the ith Fox stays awake for
Ai (1 ≤ Ai ≤ 23) hours, then sleeps for Si (1 ≤ Si ≤ 23) hours,
repeating this pattern indefinitely (2 ≤ Ai + Si ≤ 24). At the start
of your treasure-nabbing attempt, the ith Fox is
exactly Oi (0 ≤ Oi < Ai + Si) hours into its cycle.
There are T (1 ≤ T ≤ 20) scenarios as described above. For each one,
you'd like to determine how soon all of the Foxen will be
simultaneously asleep, allowing you to grab their treasure, or if this
will simply never happen.
Input
Line 1: 1 integer, T
For each scenario:
Line 1: 1 integer, N
Next N lines: 3 integers, Ai, Si, and Oi, for i = 1..N
Output
For each scenario:
Line 1: 1 integer, the minimum number of hours after the start to
wait until all of the Foxen are asleep during the same hour. If this
will never happen, output the string "Foxen are too powerful" (without
quotes) instead.
Sample Input
2
2
2 1 2
2 2 1
3
1 1 0
1 1 0
1 1 1
Sample Output
6
Foxen are too powerful
My Solution works as expected when I input the given sample case and get expected output. But when I submit the code to online judge it gives clipped error. Now there is no detail of the error which makes it difficult to find what the problem is.
Here is the solution which I have worked so far:
# ai is awake hours
# si is sleep hours.
# ai + si <= 24.
# False == sleep. True == awake.
datasets = int(raw_input());
foxen = [];
number_of_foxen = 0;
foxes = [];
class fox:
def __init__(self, a, s, i):
self.awake = a;
self.sleep = s;
self.current = i;
awake = 0;
sleep = 0;
current = 0;
def next(self):
if ( self.sleep + self.awake-1 > self.current ) :
self.current = self.current+1;
else:
self.current = 0;
return self.current;
def check(self):
if(self.current>=self.awake):
return False;
return True;
def printdata(self):
print "awake="+str(self.awake)+" sleep="+str(self.sleep)+" current="+str(self.current);
#return "awake="+str(self.awake)+" sleep="+str(self.sleep)+" current="+str(self.current);
for i in range(0, datasets):
number_of_foxen = int(raw_input());
for j in range(0, number_of_foxen):
foxen.append(raw_input());
x = foxen[j].split();
a = fox(int(x[0]), int(x[1]), int(x[2]));
foxes.append(a);
solution = False;
for j in range(0, 48):
#print "hour number = " + str(j);
#for k in range(0, len(foxes)):
#print "fox number="+ str(k)+" "+ foxes[k].printdata()+str(foxes[k].check());
count = 0 ;
for k in range(0, len(foxes)):
if(foxes[k].check()==False):
count+=1;
#print "count = "+str(count);
#print len(foxes);
if( (int(count) == int(len(foxes))) and (solution == False) ):
#print "this runs now *************";
solution = True;
number = j;
for k in range(0, len(foxes)):
foxes[k].next();
if(solution==True):
print number;
else:
print "Foxen are too powerful";
#print "Foxen are too powerful";
foxen = [];
number_of_foxen = 0;
foxes = [];
The biggest problem with your code is that it is unreadable. Indeed, it looks like it was written with little concept of Python's strengths. Here is my suggestion:
#!/usr/bin/env python3
"""
The Foxen's Treasure puzzle from http://wcipeg.com/problem/acmtryouts1b
"""
from sys import stdin
from itertools import cycle
from euclid import lcm
debug = True # set to False before submission to mechanical judge
class Fox:
"""A Fox cointains its defining integers and other derived
bindings such as its cycle and schedule."""
def __init__(self, trio):
(self.awake_count, self.sleep_count, self.skip_count) = trio
self.cycle = 'a' * self.awake_count + 's' * self.sleep_count
self.schedule = cycle(self.cycle)
if debug: print('<Fox: {}> cycle {}'.format(trio, self.cycle))
# handle skips by discarding the first elements
for _ in range(self.skip_count):
next(self.schedule)
def find_all_sleeping(foxes):
"""Return an hour number if all foxes are sleeping at that hour."""
# only examine the LCM of all fox periods. If not there it will never be.
lcm_period = 1
for fox in foxes:
lcm_period = lcm(lcm_period, len(fox.cycle))
for hour in range(lcm_period):
states = [next(fox.schedule) for fox in foxes]
if debug: print('{:2d} {}'.format(hour, ' '.join(states)))
if 'a' not in states:
return hour
return None
def read_trials(fp):
"""Reads the entire input at once. Returns a list of trials.
Each trial is a list of Fox."""
trials = list()
trial_count = int(fp.readline())
for trial in range(trial_count):
if debug: print('--Read trial {}'.format(trial))
foxes = list()
fox_count = int(fp.readline())
for _ in range(fox_count):
fox = Fox([int(x) for x in fp.readline().split()])
foxes.append(fox)
trials.append(foxes)
return trials
for trial, foxes in enumerate(read_trials(stdin)):
if debug: print('--Run trial {}'.format(trial))
hour = find_all_sleeping(foxes)
if hour is None:
print('Foxen are too powerful')
else:
print(hour)
I suspect that the first concern is that it looks much longer than the OP; that is true, but if you take out the debugging code which shows how things are happening, and the docstrings that explain why it is doing things, it's actually a few line shorter than the OP.
The main loop of the OP is too long to understand without significant study, and a whole bunch of bad variable names makes that even harder. In contrast, there are places here where a value is given a name only to make the code more explicit about what an input line means. You'll find a number of
for _ in range(trial)
to show that the loop value is not used. This is a frequent idiom when dealing with fixed format input.
The Fox representation keeps the inner workings in the problem space. As noted in the exercise page, it makes more sense to look at things as a concurrence between sequences:
--Read trial 0
<Fox: [2, 1, 2]> cycle aas
<Fox: [2, 2, 1]> cycle aass
the offsets skip_count are not shown here, but they are clear in the trial run.
The input from the datafile is all kept inside read_trials() instead of scattered through the code. This confines the mess to one place rather than distributing it through the code. We know from the puzzle instructions that the datafile will not be large enough to care about. read_trials(fp) also takes a file-like object which allows it to read from an actual file, a StringIO buffer, or the standard input.
Once the Fox schedule generator is initialized, itertools.cycle will give an unending supply of the next letter in the sequence; it does the wrap-around for you.
It is worth noting that the primary data structure trials is a plain old list because it doesn't need anything more than that.
I've gotten a little weary of bad code being answered with worse code. Sure, this could be considered way more than the needs of an electronic judge where only the output matters. Contrariwise, I'm still puzzled by bits like (solution == False), a main loop that is 42 lines long and split between the top and bottom of the file, variables like i and j which convey no intent, the memory burden of False == awake (or did I mix them up?), dead code, no-op code, `range(0, n) and a whole bunch of magic numbers throughout.
Sure, you can code like the code doesn't matter, but if you are teaching yourself to code it is good to practice good practice. Yeah, you might never look at this piece of code again, but if you ain't gonna learn it now, then when?
In case you feel it a cheat to have imported lcm() there's no reason to write it a second time, so I referenced a homebrew package of which the relevant lines are:
def gcd(a, b):
"""Return the Greatest Common Divisor of a and b."""
while b:
a, b = b, a % b
return a
def lcm(a, b):
"""Return the Least Common Multiple of a and b."""
return abs(a * b) // gcd(a, b)
Jorge was correct in his comment, there doesn't appear to be any problem with your algorithm other than the arbitrary 48 hour cuttoff.
However:
1) your print statements do not use the correct syntax for Python 3+. For example, your final print statement print "Foxen are too powerful"; must be changed to work in Python 3, try print ('Foxen are too powerful') instead.
2) I'm seeing some odd C/MatLab-like syntax as well, lines being ended by a semicolon, and double brackets surrounding conditions in your if statements. This probably isn't a problem, but depending on how picky the system you are submitting the answer to is, you may want to clean it up a little.
3) Definitely increase the cutoff time for your search. I'd recommend a reasonably large value, on the order of 10,000 hours, just to be sure that it won't be a factor.
I've taken the liberty of making all of the above changes so I'm posting the resultant code now:
# ai is awake hours
# si is sleep hours.
# ai + si <= 24.
# False == sleep. True == awake.
datasets = int(raw_input())
foxen = []
number_of_foxen = 0
foxes = []
class fox:
def __init__(self, a, s, i):
self.awake = a
self.sleep = s
self.current = i
awake = 0
sleep = 0
current = 0
def next(self):
if ( self.sleep + self.awake-1 > self.current ):
self.current = self.current+1
else:
self.current = 0
return self.current
def check(self):
if(self.current>=self.awake):
return False
return True
def printdata(self):
print ("awake="+str(self.awake)+" sleep="+str(self.sleep)+" current="+str(self.current))
#return ("awake="+str(self.awake)+" sleep="+str(self.sleep)+" current="+str(self.current))
for i in range(0, datasets):
number_of_foxen = int(raw_input())
for j in range(0, number_of_foxen):
foxen.append(raw_input())
x = foxen[j].split()
a = fox(int(x[0]), int(x[1]), int(x[2]))
foxes.append(a)
solution = False
for j in range(0, 10000):
#print ("hour number = " + str(j))
#for k in range(0, len(foxes)):
#print ("fox number="+ str(k)+" "+ foxes[k].printdata()+str(foxes[k].check()))
count = 0
for k in range(0, len(foxes)):
if(foxes[k].check()==False):
count+=1
#print ("count = "+str(count))
#print (len(foxes))
if (int(count) == int(len(foxes)) and (solution == False)):
#print ("this runs now *************")
solution = True
number = j
for k in range(0, len(foxes)):
foxes[k].next()
if(solution == True):
print (number)
else:
print ("Foxen are too powerful")
#print ("Foxen are too powerful")
foxen = []
number_of_foxen = 0
foxes = []
Enjoy and Good Luck!
Interesting problem, here's my code:
import sys
# Globals
debugLevel = 0
fileMode = True # True if loading data from a file.
# Constants
AWAKE = 0
ASLEEP = -1
def gcd(a, b):
"""Return greatest common divisor using Euclid's Algorithm."""
while b:
a, b = b, a % b
return a
def lcm(a, b):
"""Return lowest common multiple."""
return a * b // gcd(a, b)
def readData(f):
''' Read in the problem data and store in data structures
'''
numTrials = int(f.readline().strip())
if debugLevel >= 4:
print("Num trials: ", numTrials)
trialData = []
for _ in range(numTrials):
numFoxen = int(f.readline().strip())
allFoxenHoursInfo = []
for _ in range(numFoxen):
aFoxHoursInfo = f.readline().split()
aFoxHoursInfo = list(map(int, aFoxHoursInfo))
allFoxenHoursInfo.append(aFoxHoursInfo)
trialData.append((numFoxen, allFoxenHoursInfo))
if debugLevel >= 8:
print("Trial data\n", trialData)
return numTrials, trialData
def runTrials(trialData):
'''
Go through each lot of foxen, and their sleep/awake schedules and
See if there's a time that all of them will be asleep.
'''
global debugLevel
for trial in trialData:
numFoxen, allFoxenHoursInfo = trial
# Create a table of the status of each fox in each hour
row = [AWAKE] * (numFoxen+1)
row[0] = 0
hoursTable = [row]
# Cycle length for each fox is the number of hours they spend awake then asleep.
cycleLength = [0] * (numFoxen)
# This is the number of hours into the cycle each fox is at the start
startingPosInCycle= [0] * (numFoxen)
# Initialise the first row
for fox in range(numFoxen):
cycleLength[fox] = allFoxenHoursInfo[fox][0] + allFoxenHoursInfo[fox][1] # Time awake plus time asleep
startingPosInCycle[fox] = allFoxenHoursInfo[fox][2] # % cycleLength[fox]
if startingPosInCycle[fox] >= allFoxenHoursInfo[fox][0]:
hoursTable[0][fox+1] = ASLEEP
if debugLevel >= 4:
print("Initial table: ", hoursTable)
# lcm = lowest common multiple and it's implemented above.
# For this problem, we only need to look at the lcm of all the cycle lengths for the foxen.
numIterations = 1
for fox in range(numFoxen):
numIterations = lcm(numIterations, cycleLength[fox])
# Go around a loop adding a new row to the table for each new hour containing the updated
# statuses of each fox.
for hourNum in range(1, numIterations):
allFoxesSleeping = False
# Update our hours table by creating a new row and calculating the status of each fox
newRow = [AWAKE] * (numFoxen+1)
newRow[0] = hourNum
for fox in range(numFoxen):
currentPosInCycle = (startingPosInCycle[fox] + hourNum) % cycleLength[fox]
if currentPosInCycle >= allFoxenHoursInfo[fox][0]:
newRow[fox+1] = ASLEEP
hoursTable.append(newRow)
if debugLevel >= 4:
print("Hours table\n", hoursTable)
# See if all foxen are sleeping, if they are, success
numFoxesSleeping = hoursTable[hourNum].count(ASLEEP)
if numFoxesSleeping == numFoxen:
allFoxesSleeping = True
print(hourNum)
break
if not allFoxesSleeping:
print('Foxen are too powerful')
def main():
'''Reads, runs, and outputs problem specific data.'''
# Initialisation
#strDir = ".\\"
# if fileMode:
# dataSource = open(strDir + "DataFile.txt", 'r')
# else:
dataSource = sys.stdin
# Read in the input data.
numTrials, trialData = readData(dataSource)
# Run each trial, outputting the result of that trial
runTrials(trialData)
sys.stdout.flush()
# Cleanup
# if fileMode:
# dataSource.close()
if __name__ == '__main__':
main()
Unfortunately, it does not pass the judge either. I have no idea why. I get this output:
Test case #1: WA [0.178s, 3628K] (0/1) (Details)
Your Output (clipped)
6
Foxen are too powe
Final score: 0/1
Interesting problem. I have emailed the author, because there is an inconsistency in the problem definition and the sample input data. He says this: Oi (0 ≤ Oi < Ai + Si) but then gives 1 1 1 on the last line of sample input data. And 1 is not strictly less than 1+1.
So who knows what other data the judge might be using...
The bit at the bottom that is commented out re files, lets me work with files and an IPython console rather than a Python console and pasting the data in, which I find slow and annoying.
Also, it's a little strange I reckon to not be able to see the data the judge is using. Surely seeing the data you are working against would enable the problem to be run and debugged offline, then when it's going, a new online submit could be done.