[Tutor] problem with circular list
Danny Yoo
dyoo@hkn.eecs.berkeley.edu
Sun, 22 Jul 2001 12:10:43 -0700 (PDT)
On Sun, 22 Jul 2001, Tim Condit wrote:
> I found this problem and thought it would be fun, but it's got me
> stumped. The full text is at
> http://www.karrels.org/Ed/ACM/weur94p/prob_b.html . To sum it up, there
> is a king, an executioner, and a variable number of condemned prisoners.
Ah, the Josephus problem!
> Every year at the games, the prisoners are lined up, and starting at the
> first prisoner, the executioner counts off syllables of a song or
> nursery rhyme from his youth (enie, menie, miney, moe... ) and executes
> the prisoner he stops on. The same nursery rhyme is used for the whole
> "game". The last prisoner is set free. I looked around, and found some
> info about circular linked lists in C, but they are built using
> pointers. So I devised my own routine, which doesn't work. :)
>
> I figured for P number of prisoners, and S number of syllables,
> something like this would work:
>
> def prisoner(P, S)
> Plist = range(P)
> pos = S # current position of syllable count
> while len(Plist > 1):
> try:
> Plist.remove(prisoner referred to by pos)
> except:
> dist_to_end = len(Plist) - (index of pos)
> pos = S - dist_to_end # wrap to front of line
> Plist.remove(Plist[pos])
The only thing that might be missing is the moving of your pos; otherwise,
you'll alwasy be removing the Sth person. Something like:
pos = pos + S
should be part of your pseudocode.
If S = 2, for example, we want to make sure that we'll be eliminating the
"even" numbered people first.
> There are a few things that this does not address at all, like dealing
> with S larger than P, but I'll get to that. This is what I have so far:
>
> def prisoner(P, S):
> import operator
>
> S = S - 1
> Plist = range(P)
> pos = S
> while len(Plist) > 1:
> try:
> print "(try) removing prisoner %d" % (Plist[pos])
> Plist.remove(Plist[pos])
> pos = pos + S
> except IndexError:
Side note: you can avoid depending on IndexError altogether by using the
"modulo" operator '%'. The modulo operator is traditionally used for
things that "wrap around":
###
>>> for i in range(10):
... print i % 3
...
0
1
2
0
1
2
0
1
2
0
###
Anyway, let's look again at your code:
> while len(Plist) > 1:
> try:
> print "(try) removing prisoner %d" % (Plist[pos])
> Plist.remove(Plist[pos])
> pos = pos + S
> except IndexError:
> pos = pos + S
> pos = pos - len(Plist)
> Plist.remove(Plist[pos])
> print "last man standing: %d" % (Plist[0] + 1)
>
>
> The problem I'm having is that pos is a number, but it needs to a
> location, if that makes sense. The first time through, until pos
> exceeds len(Plist), it *appears* to work correctly, even though it's
> not. After that, it bombs out.
You don't want to use remove(): it removes items from a list based on
an element's value, not position:
###
Help on built-in function remove:
remove(...)
L.remove(value) -- remove first occurrence of value
###
What you'll want to use, instead, is the deleting operator, 'del':
###
>>> mylist = range(10)
>>> del mylist[0]
>>> mylist
[1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> del mylist[1]
>>> mylist
[1, 3, 4, 5, 6, 7, 8, 9]
###
del would be a more appropriate way to... execute the deletion.
Hope this helps!