Dancing Links

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Dancing Links相关的知识,希望对你有一定的参考价值。

Dancing Links用来解决如下精确匹配的问题:

技术分享

选择若干行使得每一列恰好有一个1。Dancing Links通过对非零元素建立双向十字循环链表。上面的例子建立的链表如下所示:

技术分享

计算的时候使用搜索的策略。每次选出1最少的一列,比如c,然后选择这一列中的某一行,比如r,(r,c)=1,然后r中所有1所在的列,那些其他行这些列有1的都删掉(这些行不会在r算入答案后也在答案里,否则就有某些列多于一个1出现)。然后这就变成一个规模更小的问题,继续搜索。无解时要回溯。

  1 class CDancingLinks
  2 {
  3 protected:
  4     struct DancingLinksNode
  5     {
  6         DancingLinksNode* left;
  7         DancingLinksNode* right;
  8         DancingLinksNode* down;
  9         DancingLinksNode* up;
 10         int col;
 11         int row;
 12     };
 13 
 14     typedef DancingLinksNode Node;
 15 
 16     int *m_columnEleNumbers;
 17     int m_colNumber;
 18     int m_rowNumber;
 19     Node* m_pool;
 20     Node** m_head;
 21     int m_curUsePoolIndex;
 22 
 23 
 24 
 25 
 26 
 27     void _Remove(Node* cur)
 28     {
 29         --m_columnEleNumbers[cur->col];
 30         for(Node* p=cur->down;p!=cur;p=p->down)
 31         {
 32             p->left->right=p->right;
 33             p->right->left=p->left;
 34         }
 35     }
 36 
 37     void _Resume(Node* cur)
 38     {
 39         ++m_columnEleNumbers[cur->col];
 40         for(Node* p=cur->up;p!=cur;p=p->up)
 41         {
 42             p->left->right=p;
 43             p->right->left=p;
 44         }
 45     }
 46 
 47 
 48 
 49     bool _SearchSolution(const int depth,std::vector<int> &solution)
 50     {
 51         Node* p=_GetNode(0);
 52         if(p->left==p) return true;
 53 
 54         int Min=m_rowNumber+1;
 55         int MinColumnIndex=0;
 56         for(Node* q=p->left;q!=p;q=q->left)
 57         {
 58             if(m_columnEleNumbers[q->col]<Min)
 59             {
 60                 Min=m_columnEleNumbers[q->col];
 61                 MinColumnIndex=q->col;
 62             }
 63         }
 64 
 65 
 66         for(Node* q=_GetNode(MinColumnIndex)->down;q!=_GetNode(MinColumnIndex);q=q->down)
 67         {
 68             _Remove(q);
 69             solution.push_back(q->row);
 70             for(Node* rr=q->right;rr!=q;rr=rr->right) _Remove(rr);
 71             if(_SearchSolution(depth+1,solution)) return true;
 72             for(Node* rr=q->left;rr!=q;rr=rr->left) _Resume(rr);
 73             solution.pop_back();
 74             _Resume(q);
 75         }
 76 
 77         return false;
 78     }
 79 
 80     Node* _GetNode(int id) { return m_pool+id; }
 81 
 82     void _ReleaseMemory()
 83     {
 84          if(m_columnEleNumbers)
 85         {
 86             delete[] m_columnEleNumbers;
 87             m_columnEleNumbers=nullptr;
 88         }
 89 
 90         if(m_pool)
 91         {
 92             delete[] m_pool;
 93             m_pool=nullptr;
 94         }
 95         if(m_head)
 96         {
 97             delete[] m_head;
 98             m_head=nullptr;
 99         }
100     }
101 
102 public:
103 
104     CDancingLinks():m_colNumber(-1),m_rowNumber(-1),
105         m_columnEleNumbers(nullptr),m_pool(nullptr),m_head(nullptr) {}
106 
107     /***
108       列下标为[1,Column]
109     ***/
110     CDancingLinks(const int Column,const int Row):
111         m_columnEleNumbers(nullptr),m_pool(nullptr),m_head(nullptr)
112     {
113         SetSize(Column,Row);
114     }
115 
116     /***
117       列下标为[1,Column]
118     ***/
119     void SetSize(const int Column,const int Row)
120     {
121         m_colNumber=Column;
122         m_rowNumber=Row;
123 
124         _ReleaseMemory();
125 
126         m_columnEleNumbers=new int[m_colNumber+1];
127         m_pool=new Node[m_colNumber*(m_rowNumber+1)+1];
128         m_head=new Node*[m_rowNumber+1];
129         Clear();
130     }
131 
132     void Clear()
133     {
134         for(int i=0;i<=m_colNumber;++i)
135         {
136             Node* cur=_GetNode(i);
137             cur->left=((i==m_colNumber)?_GetNode(0):_GetNode(i+1));
138             cur->right=((0==i)?_GetNode(m_colNumber):_GetNode(i-1));
139             m_columnEleNumbers[i]=0;
140 
141             cur->up=cur->down=_GetNode(i);
142             cur->col=i;
143             cur->row=0;
144         }
145         for(int i=1;i<=m_rowNumber;++i) m_head[i]=NULL;
146         m_curUsePoolIndex=m_colNumber+1;
147     }
148 
149     ~CDancingLinks()
150     {
151         _ReleaseMemory();
152     }
153 
154     void AddElement(const int row,const int col)
155     {
156 
157         Node* cur=m_pool+(m_curUsePoolIndex++);
158 
159         cur->up=_GetNode(col);
160         cur->down=_GetNode(col)->down;
161         m_pool[col].down->up=cur;
162         m_pool[col].down=cur;
163 
164 
165         if(m_head[row]==NULL)
166         {
167             m_head[row]=cur->left=cur->right=cur;
168         }
169         else
170         {
171             cur->left=m_head[row]->left;
172             cur->right=m_head[row];
173             m_head[row]->left->right=cur;
174             m_head[row]->left=cur;
175         }
176         ++m_columnEleNumbers[col];
177         cur->col=col;
178         cur->row=row;
179     }
180 
181     bool GetSolution(std::vector<int> &Solution)
182     {
183         return _SearchSolution(0,Solution);
184     }
185 };

 

以上是关于Dancing Links的主要内容,如果未能解决你的问题,请参考以下文章

Dancing Links 专题总结

dancing links

HDU 5046 Airport ( Dancing Links 反复覆盖 )

HDU 3335 Divisibility dancing links 重复覆盖

HDU5046 Airport dancing links 重复覆盖+二分

Dancing Links