Solving a programming-contest using Python [closed] - python

It's difficult to tell what is being asked here. This question is ambiguous, vague, incomplete, overly broad, or rhetorical and cannot be reasonably answered in its current form. For help clarifying this question so that it can be reopened, visit the help center.
Closed 11 years ago.
I found this problem, which I thought would be interesting to solve but couldn't really come up with a correct solution-
Inside a room, there is a monster with
N heads, and a human (with 1 head).
The human has two laser guns. The
first gun, A destroys C1 heads when
fired and the second gun,B destroys C2
heads when fired [The guns may destroy
both the monster's as well as human
heads, but the guns prioritize monster
heads over human ones].
Also, if after the firing of the gun
the monster has a positive non-zero
number of heads left, the monster will
grow additional heads. The monster
grows G1 heads when gun A is used and
it grows G2 heads when gun B is used.
The problem is to input N, C1, C2, G1
and G2, then find out what would be
the shortest combination of
gun-choice(A or B) the human must use
to kill the monster(the monster dies
when No. of heads=0).
[Note- this problem is from a programming contest that has already ended]
I tried approaching this problem using recursion but found myself clueless about how to actually come up with the solution. So, if you could give some hints how to approach the problem, that'd be great.

First of all: Dijkstra's is not the optimal solution :)
Given this sentence: "The guns may destroy both the monster's as well as human heads"
I take it if you can shoot 10 heads and the monster only has 5 heads, you can't kill it because that would kill you too. Is that correct?
In any case, any solution would be of the form:
ABABAABBABBB... (some string of A's and B's)
On the final hit you kill C1 or C2 heads. On every other hit you kill C1 - G1 or C2 - G2 heads.
If the final hit is from A, you have to destroy N-A heads with shots doing (C1-G1) or (C2-G2) damage.
If the final hit is from B, you have to destroy N-B heads with shots doing (C1-G1) or (C2-G2) damage.
Any K can be represented in the form:
X*i + Y*j = K
Of course, X and Y have to be coprime, etc.
K heads can be destroyed by i shots of damage X and j shots of damage Y.
You can find out the values of i and j with the extended greatest common divisor algorithm.
Solve for X = (C1-G1), Y = (C2-G2) and K = (N-A)
Also solve for X = (C1-G1), Y = (C2-G2) and K = (N-B)
The smallest answer is the correct one :)
That's it :)

Ah, I see you have found a solution in C++ already using Dijkstra's algorithm: http://hashsamrat.blogspot.com/2010/10/surviving-monster-programming-problem.html
However, you seem to be thinking about 'recursion' and other methods.
The solution is separate than the implementation. Thus what you really want to do would be to use the same algorithm (Dijkstra's, which is just breadth-first search carefully done so you visit the shortest paths first), but in python rather than C++.
You could just copy the C++ line-by-line, using python idioms to make the code cleaner and more elegant. But you'll still be using the same algorithm. (Alternatively, you could Google for the hundreds of ways people have implemented Dijkstra's in python. Or you could write it yourself; all you need is a priority queue (see wikipedia), and if time isn't an issue, you can write a poorly-performing priority queue in the form of a dictionary-of-lists.)
edit: Thinking about it, if by "shortest set of choices" you just mean "fewest gunshots", you don't really need Dijkstra's at all; it's just breadth-first-search (which is equivalent to Dijkstra's when all edges have weight 1).
In particular, the logic to generate a new node is as follows:
def howManyHeadsLeft(currentHeads, damage, regen):
newHeads = heads - damage
if {this results in blowing off our own head} and newHeads>0: #modify depending on assumptions
# we killed ourselves without taking monster down with us
return {} # the empty set of possible search nodes
else:
newHeads += regen
# we could just say return {newHeads} here,
# but that would be terribly slow to keep on searching the same
# state over and over again, so we use a cache to avoid doing that
# this is called dynamic programming
if {we have never seen newHeads before}:
return {newHeads}
else
return {}
def newSearchNodes(currentHeads):
return howManyHeadsLeft(currentHeads, atypeDamage, atypeRegen) | howManyHeadsLeft(currentHeads, btypeDamage, btypeRegen)
The 'goal' condition for the search is having just enough damage to kill the hydra without killing yourself (modify as appropriate depending on assumptions):
heads==1+atypeDamage or heads==1+btypeDamage
Of course it is also possible that no solution exists (regen > damage for both types of guns), in which case this algorithm might run forever, but could probably be modified to terminate.

Related

How do I stop my backtracking algorithm once I find and answer?

I have wrote this code for solving a problem given to me in class, the task was to solve the "toads and frogs problem" using backtracking. My code solves this problem but does not stop once it reaches the solution (it keeps printing "states" showing other paths that are not a solution to the problem), is there a way to do this?. This is the code:
def solution_recursive(frogs):
#Prints the state of the problem (example: "L L L L _ R R R R" in the starting case
#when all the "left" frogs are on the left side and all the "right" frogs are on
#the right side)
show_frogs(frogs)
#If the solution is found, return the list of frogs that contains the right order
if frogs == ["R","R","R","R","E","L","L","L","L"]:
return(frogs)
#If the solution isn't the actual state, then start (or continue) recursion
else:
#S_prime contains possible solutions to the problem a.k.a. "moves"
S_prime = possible_movements(frogs)
#while S_prime contains solutions, do the following
while len(S_prime) > 0:
s = S_prime[0]
S_prime.pop(0)
#Start again with solution s
solution_recursive(s)
Thanks in advancement!
How do I stop my backtracking algorithm once I find an answer?
You could use Python exception facilities for such a purpose.
You could also adopt the convention that your solution_recursive returns a boolean telling to stop the backtrack.
It is also a matter of taste or of opinion.
I'd like to expand a bit on your recursive code.
One of your problems is that your program displays paths that are not the solutions. This is because each call to solution_recursive starts with
show_frogs(frogs)
regardless of whether frogs is the solution or not.
Then, you say that the program is continuing even after the solution has been found. There are two reasons for this, the first being that your while loop doesn't care about whether the solution has been found or not, it will go through all the possible moves:
while len(S_prime) > 0:
And the other reason is that you are reinitializing S_prime every time this function is called. I'm actually quite amazed that it didn't enter an infinite loop just checking the first move over and over again.
Since this is a problem in class, I won't give you an exact solution but these problems need to be resolved and I'm sure that your teaching material can guide you.

How does Python stops itself a recurence?

Imagine I calculate the Fibonacci sequence following the (obviously inefficient) recursive algorithm :
def Fibo(n):
if n <= 1:
return(n)
else:
return(Fibo(n-2) + Fibo(n-1))
then my question is : how does Python known it has to stop the recurrence at n=0 ?
After all, if I call Fibo(-12), Python obviously answers -12, so why does it stop the recursion at n=0 while calling Fibo(12) for instance ?
Edit after a few comments :
This question has nothing to do with the mathematical concept of recurrence. I know recurrence stops at the initialized point. I would like to understand how recurrence are implemented in computer. For me ti is absolutely not clear while a computer should stop while there is no explicit stop command. What prevents here Fibo(0)=Fibo(-1)+Fibo(-2) to continue endlessly ? Because after all I precised that Fibo(-1)=-1, Fibo(-2)=-2, ... and I might want to summ all negative numbers as well ...
I confess in the last case I would prefer do a while loop.
It's functional, so it doesn't run, so it also doesn't stop. You are (still) thinking in terms of iterative programming and assume some kind of loop here which needs to stop at some time. This is not the case.
Instead in this paradigm you just state that the return value is the sum of the prior two numbers. At this point you don't care how the prior numbers are produced, here you just assume that they already exist.
Of course they don't and you will have to compute them as well but still this is not a loop which needs a stop. Instead it is a recursion which has an anchor. With each recursion step the values will become smaller and smaller and once they reach a value below 2 you just return 0 or 1 without any further recursion. This is your anchor.
Feel free to think of it as a "stopping point" but be aware that there is no loop happening which you need to break out of or similar.

Python performance questions for: toggling +/-1, set instantiation, set membership check

I've been working on the following code which sort of maximizes the number of unique (in lowest common denominator) p by q blocks with some constraints. It is working perfectly. For small inputs. E.g. input 50000, output 1898.
I need to run it on numbers greater than 10^18, and while I have a different solution that gets the job done, this particular version gets super slow (made my desktop reboot at one point), and this is what my question is about.
I'm trying to figure out what is causing the slowdown in the following code, and to figure out in what order of magnitude they are slow.
The candidates for slowness:
1) the (-1)**(i+1) term? Does Python do this efficiently, or is it literally multiplying out -1 by itself a ton of times?
[EDIT: still looking for how operation.__pow__ works, but having tested setting j=-j: this is faster.]
2) set instantiation/size? Is the set getting too large? Obviously this would impact membership check if the set can't get built.
3) set membership check? This indicates O(1) behavior, although I suppose the constant continues to change.
Thanks in advance for insight into these processes.
import math
import time
a=10**18
ti=time.time()
setfrac=set([1])
x=1
y=1
k=2
while True:
k+=1
t=0
for i in xrange(1,k):
mo = math.ceil(k/2.0)+((-1)**(i+1))*(math.floor(i/2.0)
if (mo/(k-mo) not in setfrac) and (x+(k-mo) <= a and y+mo <= a):
setfrac.add(mo/(k-mo))
x+=k-mo
y+=mo
t+=1
if t==0:
break
print len(setfrac)+1
print x
print y
to=time.time()-ti
print to

How to try all possible paths?

I need to try all possible paths, branching every time I hit a certain point. There are <128 possible paths for this problem, so no need to worry about exponential scaling.
I have a player that can take steps through a field. The player
takes a step, and on a step there could be an encounter.
There are two options when an encounter is found: i) Input 'B' or ii) Input 'G'.
I would like to try both and continue repeating this until the end of the field is reached. The end goal is to have tried all possibilities.
Here is the template, in Python, for what I am talking about (Step object returns the next step using next()):
from row_maker_inlined import Step
def main():
initial_stats = {'n':1,'step':250,'o':13,'i':113,'dng':0,'inp':'Empty'}
player = Step(initial_stats)
end_of_field = 128
# Walk until reaching an encounter:
while player.step['n'] < end_of_field:
player.next()
if player.step['enc']:
print 'An encounter has been reached.'
# Perform an input on an encounter step:
player.input = 'B'
# Make a branch of player?
# perform this on the branch:
# player.input = 'G'
# Keep doing this, and branching on each encounter, until the end is reached.
As you can see, the problem is rather simple. Just I have no idea, as a beginner programmer, how to solve such a problem.
I believe I may need to use recursion in order to keep branching. But I really just do not understand how one 'makes a branch' using recursion, or anything else.
What kind of solution should I be looking at?
You should be looking at search algorithms like breath first search (BFS) and depth first search (DFS).
Wikipedia has this as the pseudo-code implementation of BFS:
procedure BFS(G, v) is
let Q be a queue
Q.enqueue(v)
label v as discovered
while Q is not empty
v← Q.dequeue()
for all edges from v to w in G.adjacentEdges(v) do
if w is not labeled as discovered
Q.enqueue(w)
label w as discovered
Essentially, when you reach an "encounter" you want to add this point to your queue at the end. Then you pick your FIRST element off of the queue and explore it, putting all its children into the queue, and so on. It's a non-recursive solution that is simple enough to do what you want.
DFS is similar but instead of picking the FIRST element form the queue, you pick the last. This makes it so that you explore a single path all the way to a dead end before coming back to explore another.
Good luck!

Why is my program ending early?

I was recently able to get this to run thanks to all of your help, but I cant figure out why my program is ending here. Looking at it, if answer == 3: should just bring you to the next encounter, but my program is closing. Am I missing something?
# First Encounter (main program really)
def fi_en():
global pow, cun, per
print"""
It smells of damp vegetation, and the air is particularly thick. You can
hear some small animals in the distance. This was a nice place to sleep.
1. Stay close, find some cover, and wait for food to show up.
2. Explore the nearby marsh & find the nearest river, following it downstream.
3. Walk towards the large mysterious mountain in the distance.
"""
answer = int(raw_input(prompt))
if answer == 1:
cun_one = roll_3d6()
if cun_one <= cun - 2:
print"""Time passes as eventually you capture some varmints.
You feel slightly more roguish."""
cun = cun + 1
fi_en()
else:
print """Time passes and a group of slavers marches into right
where you are hiding in the woods. They locate you, capture you, and haul you
away for a lifetime of servitude in the main city.
Goodbye %s""" % name
elif answer == 2:
power = roll_3d6()
if power <= pow - 4:
print"""You trudge through the marshes until you eventually reach
a large river. Downstream from the river is a large temple covered in vines,
you walk towards it. You feel more powerful."""
pow = pow + 2
te_en()
else:
print """The vegetation here wraps itself around your legs making
it impossible to move. You will most likely die here in the vegetation.
Goodbye %s.""" % name
elif answer == 3:
cun_two = roll_3d6()
if cun_two <= cun:
print """You make your way towards the mountain and you encounter
a really large group of devil dogs guarding the entrance to the mountain."""
dd_en()
else:
print"You have gotten lost and ended up right where you started."
fi_en()
And my output is:
It smells of damp vegetation, and the air is particularly thick. You can
hear some small animals in the distance. This was a nice place to sleep.
1. Stay close, find some cover, and wait for food to show up.
2. Explore the nearby marsh & find the nearest river, following it downstream."
3. Walk towards the large mysterious mountain in the distance.
> 3
Raymond-Weisss-MacBook-Pro:lod Raylug$
It sounds to me like you're missing a really large group of devil dogs. Are you sure you want to fix this?
You haven't defined your globals anywhere. You have no "else" statement within condition three, so since cun_one is not less than/equal to your undefined cun variable, there is nothing else to do when answer == 3.
Deleted everything since you already got it working, just a comment.
You can use input('Prompt') since it automatically becomes an int, raw_input converts the input to a string, and then you are converting that string to an int, which is unnecessary.

Categories