Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>Here's my take on a solution. As Tim Peters pointed out, this is a Hamiltonian path problem. So the first step is to generate the graph in some form.</p> <p>Well the zeroth step in this case to generate prime numbers. I'm going to use a sieve, but whatever prime test is fine. We need primes upto <code>2 * n</code> since that is the largest any two numbers can sum to.</p> <pre><code>m = 8 n = m + 1 # Just so I don't have to worry about zero indexes and random +/- 1's primelen = 2 * m prime = [True] * primelen prime[0] = prime[1] = False for i in range(4, primelen, 2): prime[i] = False for i in range(3, primelen, 2): if not prime[i]: continue for j in range(i * i, primelen, i): prime[j] = False </code></pre> <p>Ok, now we can test for primality with <code>prime[i]</code>. Now its easy to make the graph edges. If I have a number i, what numbers can come next. I'll also make use of the fact that i and j have opposite parity.</p> <pre><code>pairs = [set(j for j in range(i%2+1, n, 2) if prime[i+j]) for i in range(n)] </code></pre> <p>So here <code>pairs[i]</code> is set object whose elements are integers j such that <code>i+j</code> is prime.</p> <p>Now we need to walk the graph. This is really where the time consuming part is and all further optimizations will be done here.</p> <pre><code>chains = [ ([], set(range(1, n)) ] </code></pre> <p><code>chains</code> is going to keep track of the valid paths as we walk them. The first element in the tuple will be your result. The second element is all the unused numbers, or unvisited nodes. The idea is to take one chain out of the queue, take a step down the path and put it back.</p> <pre><code>while chains: chain, unused = chains.pop() if not chain: # we haven't even started, all unused are valid valid_next = unused else: # We need numbers that are both unused and paired with the last node # Using sets makes this easy valid_next = unused &amp; pairs[chains[-1]] for num in valid_next: # Take a step to the new node and add the new path back to chains # Reminder, its important not to mutate anything here, always make new objs newchain = chain + [num] newunused = unused - set([num]) chains.append( (newchain, newunused) ) # are we done? if not newunused: print newchain chains = False </code></pre> <p>Notice that if there is no valid next step, the path is removed without a replacement.</p> <p>This is really memory inefficient, but runs in a reasonable time. The biggest performance bottleneck is walking the graph, so the next optimization would be popping and inserting paths in intelligent places to prioritize the most likely paths. It might be helpful to use a <code>collections.deque</code> or different container for your chains in that case.</p> <p>EDIT</p> <p>Here is an example of how you can implement your path priority. We will assign each path a score and keep the <code>chains</code> list sorted by this score. For a simple example I will suggest that paths containing "harder to use" nodes are worth more. That is for each step on a path the score will increase by <code>n - len(valid_next)</code> The modified code will look something like this.</p> <pre><code>import bisect chains = ... chains_score = [0] while chains: chain, unused = chains.pop() score = chains_score.pop() ... for num in valid_next: newchain = chain + [num] newunused = unused - set([num]) newscore = score + n - len(valid_next) index = bisect.bisect(chains_score, newscore) chains.insert(index, (newchain, newunused)) chains_score.insert(index, newscore) </code></pre> <p>Remember that insertion is <code>O(n)</code> so the overhead of adding this can be rather large. Its worth doing some analysis on your score algorithm to keep the queue length <code>len(chains)</code> managable.</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload