Advertisement
nlw

DLX in Python with pointers

nlw
May 9th, 2011
364
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 3.96 KB | None | 0 0
  1. ## Knuth's "Algorithm X" implemented with Dancing Links, _implemented
  2. ## with actual pointers_, and all in Python.
  3. ##
  4. ## Coded by Nicolau Werneck <nwerneck@gmail.com> in 2011-05-09
  5.  
  6. class Node():
  7.     def __init__(self):
  8.         self.u=self
  9.         self.d=self
  10.         self.l=self
  11.         self.r=self
  12.         self.c=self
  13.  
  14.     def l_sweep(self):
  15.         x=self.l
  16.         while x != self:
  17.             yield x
  18.             x=x.l
  19.         else:
  20.             return
  21.  
  22.     def r_sweep(self):
  23.         x=self.r
  24.         while x != self:
  25.             yield x
  26.             x=x.r
  27.         else:
  28.             return
  29.  
  30.     def u_sweep(self):
  31.         x=self.u
  32.         while x != self:
  33.             yield x
  34.             x=x.u
  35.         else:
  36.             return
  37.  
  38.     def d_sweep(self):
  39.         x=self.d
  40.         while x != self:
  41.             yield x
  42.             x=x.d
  43.         else:
  44.             return
  45.  
  46. class Matrix():
  47.     def __init__(self, column_labels, lines):
  48.         ## The header node
  49.         self.h = Node()
  50.         h = self.h
  51.         self.hdic = {}
  52.  
  53.         ## Create the colums headers
  54.         for label in column_labels:
  55.             ## Append new nodes to column header line, reading labels
  56.             ## from input list.
  57.             h.l.r = Node()
  58.             h.l.r.l = h.l
  59.             h.l.r.r = h
  60.             h.l = h.l.r
  61.             h.l.n = label
  62.             self.hdic[label] = h.l
  63.  
  64.         ## Add lines to the matrix
  65.         for ll in lines:
  66.             last=[]
  67.             for l in ll:
  68.                 q = Node()
  69.                 ## Get column header
  70.                 c = self.hdic[l]
  71.  
  72.                 ## Add new node to column bottom.
  73.                 q.u = c.u
  74.                 q.d = c
  75.                 q.d.u = q
  76.                 q.u.d = q
  77.                 q.c = c
  78.  
  79.                 ## Tie new node to possibly existing previous row
  80.                 ## node.
  81.                 if last:
  82.                     q.l = last
  83.                     q.r = last.r
  84.                     q.l.r = q
  85.                     q.r.l = q
  86.                 ## Current node becomes "last" node from this row.
  87.                 last=q
  88.  
  89.     ## The search algorithm. First we defoine the cover and uncover
  90.     ## operations.
  91.     def cover(self,c):
  92.         c.r.l = c.l
  93.         c.l.r = c.r
  94.         for i in c.d_sweep():
  95.             for j in i.r_sweep():
  96.                 j.d.u = j.u
  97.                 j.u.d = j.d                
  98.  
  99.     def uncover(self,c):
  100.         for i in c.u_sweep():
  101.             for j in i.l_sweep():
  102.                 j.d.u = j
  103.                 j.u.d = j
  104.         c.r.l = c
  105.         c.l.r = c
  106.  
  107.     ## Now the actual recursive "search" procedure. Must be called
  108.     ## like this: m.search(0,[]). I tried to keed the code looking as
  109.     ## much as possible like the original definition from Knuth's
  110.     ## article.
  111.     def search(self, k, o_all):
  112.         if self.h.l == self.h:
  113.             for o in o_all:
  114.                 print ''.join(self.print_o(o)),
  115.             print
  116.         ## Select leftmost column
  117.         c = self.h.r
  118.         self.cover(c)
  119.         for r in c.d_sweep():
  120.             o_k = r
  121.             for j in r.r_sweep():
  122.                 self.cover(j.c)
  123.             self.search(k+1, o_all+[o_k])
  124.             ## Dunno why Knuth put this line in his code, not
  125.             ## necessary. Maybe a premature optimization in mind?
  126.             #r,c = o_k,r.c
  127.             for j in r.l_sweep():
  128.                 self.uncover(j.c)
  129.         self.uncover(c)
  130.  
  131.     ## To print the solution(s)
  132.     def print_o(self, r):
  133.         out = [r.c.n]
  134.         for x in r.r_sweep():
  135.             out.append(x.c.n)
  136.         return out
  137.  
  138. ##
  139. ## Run the damn thing
  140. if __name__ == '__main__':
  141.     cols=['a','b','c','d']
  142.     lines=[['a'],['b'],['c'],['d'],
  143.         ['a','b'],['a','c'],['a','d'],['b','c'],
  144.         ['b','d'],['c','d'],['a','b','c'],['a','b','d'],
  145.         ['a','c','d'],['b','c','d'],['a','b','c','d'],]
  146.  
  147.     m = Matrix (cols, lines)
  148.     #m.print_matrix()
  149.     m.search(0, [])
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement