Dance Chain (Dancing links) C + + implementation (pointer version)

Source: Internet
Author: User

• Accurate coverage issues

Definition of the exact coverage problem: given a matrix of 0-1, whether a set of rows can be found, so that each column in the collection contains exactly one 1.

For example, the following matrix

Contains such a collection (lines 1th, 4, 5).

• Conventional Solutions

Using Backtracking method

Each time the selected row is enumerated, it is possible to continue, if no matter how the choice can not continue, backtracking.

Here's an example of a big guy:

Original site: https://www.cnblogs.com/grenet/p/3145800.html

Matrix 1:

Let's assume that line 1th is selected as follows:

As shown in, the red line is the selected row with 3 1 in the row, the 3rd, 5, and 6 columns.

Since these 3 columns already contain 1, the three columns are marked down and the blue part of the figure. The blue section contains 3 1, respectively, in 2 rows, the 2 lines are marked with purple

By definition, 1 of the same column can have 1, so the purple two lines, and the red line of 1 conflict.

So in the next solution, the red part, the blue part, and the purple part are all useless, remove the parts and get a new matrix

Matrix 2:

rows correspond to lines 2nd, 4, 5 in Matrix 1, respectively

columns correspond to Columns 1th, 2, 4, 7 in Matrix 1, respectively

Then the problem is converted to a small point of the exact coverage problem

Select Line 1th in the new matrix, as shown in

or follow the previous steps to mark it. The red, blue, and purple sections are all removed, resulting in a new empty matrix, and a red line of 0 (with 0 indicating that the column has no 1 coverage). Description, line 1th selection is wrong

Then go back and select Line 2nd, as shown in

Follow the previous steps to mark it. Remove the red, blue, and purple sections to get a new matrix

Matrix 3:

Row corresponds to line 3rd in Matrix 2, line 5th in Matrix 1

columns correspond to columns 2nd and 4 in Matrix 2, columns 2nd and 7 in Matrix 1

Since the remaining matrices are only 1 rows and are all 1, selecting this line will solve the problem

So the solution to this problem is the 1th line in Matrix 1, the 2nd line in Matrix 2, and the 1th line in Matrix 3. The 1th, 4, and 5 lines in matrix 1

From the above solving process, the actual solution can be represented as follows

1. Select a row from the matrix

2. According to the definition, the elements of other rows in the matrix are marked

3, delete the related rows and columns of the elements, to get a new matrix

4, if the new matrix is an empty matrix, and the previous row is 1, then the end of the solution, jump to 6; The new matrix is not an empty matrix, continue to solve, jump to 1; The new matrix is an empty matrix, the previous row has 0, jumps to 5

5, the description of the previous choice is wrong, back to a previous matrix, jump to 1; If no matrix can be traced back, the problem is no solution, jump to 7

6, the solution ends, the result output

7. End of solution, output no solution message

If you do this, you will encounter the following issues:

      1. How to store the status of each step;

      2. How to output the correct results.

        The dance chain proposed by algorithmic master Donald E.knuth is an ingenious solution.

        · Dancing Links Storage Mode

        We all know that the list has the advantage of being easy to insert and remove,

        such as: A,b,c is connected sequentially,

        Delete B:    b.left.right = b.right, b.right.left = b.left;//i.e.: A.right = c, c.left = A; no change in B content reinsert B:  b.left.right = B.rig Ht.left = b; That is: A.right = B.left = B; can take advantage of the contents of B

        Looking at the key steps in the general practice-deleting rows (columns) and inserting (resuming) rows (columns), it is convenient to take advantage of these two points, not only to save space (because you do not have to re-open the matrix every step), but also to be efficient in time.

        Dancing links uses a cross cross- loop bidirectional chain .

        Cross: One line per row (.. ) list, and one more (.) For each column. ) linked list.

        Since we only consider covering those ranks, only care about 1 of the position, so will be 1 of the position to save up,

        As shown: (A well-known picture.) )

        Corresponding matrix:

        Notice the elements of the first line:

        Head and C1, C2 ... are all auxiliary elements:

        Head is primarily looking for an uncovered column and deciding whether to find a scheme, Head.right is a column label that has not yet been overwritten, and when Head.right==head indicates that all columns have been overwritten.

        C1, C2 ... Can be thought of as a column label, both the delete and restore columns will start here, and the "ingress" of the recovery column can be found after the column is deleted.

        So you can define the structure as follows:

        struct Node{node *l, *r, *u, *d, *col;int x;node (node *a = 0, node *b = 0, node *c = 0, node *d = 0,node *e = 0, int f = 0 ): L (a), R (b), U (c), D (d), Col (e), X (f) {};}

        Where l,r,u,d refers to the left, right, top, and bottom elements, col points to the row's column label element, and X is the line number.

        As for constructors ... It's just my mess ....

        Delete (remove)
              Given the definition of the exact coverage problem, our goal is to overwrite all columns, so each time we find a column that is not covered.
              Suppose we find a column labeled C, let's pretend we want to overwrite this column first.
              The first thing to do is delete this column, and we just need to remove the column label on the list, because the entry column is implemented by the column label. Then no matter which line we choose to overwrite, all the rows that can overwrite this column are no longer selectable, so the row for each element ( except the column label ) on this column is deleted. however , there may be a bad situation-  c->d = = C, that cannot be overridden in this column! At this point, you should return false to indicate a decision error. If you delete this column successfully, you will naturally return true .
              The code is as follows:   
        BOOL Remove (node *c) {c->l->r = c->r, c->r->l = c->l;if (c->d = = c) return false;for (node *i = c-> D I! = C; i = i->d) for (node *j = i->r; J! = i; j = j->r) {j->u->d = J->d;j->d->u = J->u;} return true;}

        When deleting a row, also keep "Ingress", that is, line 7th: j = i->r and J! = i.

        Recovery

        Recovery is relatively simple.

        The first step: Restore the row related to the column;

        Step two: Restore the column.

        On the code:

        void Recover (node *c) {for (node *i = c->d; I! = c; i = i->d) for (node *j = i->r; J! = i; j = j->r) j->u-> D = J->d->u = J;c->l->r = C->r->l = C;}
        Body part

        The main part is the process of backtracking.

        First, to find the non-covered column, Head->right is (see the "Storage Method" section above), if head->right = = Head, the explanation to find the solution, return true.

        Then it is to delete this column, then determine the Remove function return value, if False can directly return false table is not OK.

        After the column was successfully deleted, we found that we had only deleted the related rows before, and we did not really "select" which line, so we enumerated which row to select, and deleted the column that could be overwritten by this line . Having done this, we can continue to work on the remaining non-covered columns.

        Processing the rest of the columns we still call the principal function, when it returns True, indicates that the solution has been found, the line we enumerate is of course also in the solution, the direct output. Otherwise, we will continue to try to select another line, before we recover the line that we deleted before.

        Returns False if all rows are enumerated without a workable solution.

        The code is as follows:

        BOOL DLX () {Node *c = head->r;if (c = = head) return true;if (!remove (c)) return false;for (node *i = c->d; I! = C; i = I->d) {for (node *j = i->r; J! = i; j = j->r) Remove (J->col), if (DLX ()) {printf ("%d", i->x), return true;} for (Node *j = i->r; J! = i; j = j->r) recover (j->col);} return false;}
        Summarize

        So, the pointer is flying, probably the source of the dancing links name.

        Combined code (output a set of possible solutions):


        #include <cstdio> #include <iostream> #include <cstring>using namespace std;struct node{node *l, *r, *u , *d, *col;int x;node (node *a = 0, node *b = 0, node *c = 0, node *d = 0,node *e = 0, int f = 0): L (a), R (b), U (c), D (d), C OL (E), X (f) {};} *head, *tail[100005];int N, m;bool Remove (node *c) {c->l->r = c->r, c->r->l = c->l;if (c->d = = c) Retu RN false;for (Node *i = c->d; I! = c; i = i->d) for (node *j = i->r; J! = i; j = j->r) {j->u->d = j->d; J->d->u = J->u;} return true;} void Recover (node *c) {for (node *i = c->d; I! = c; i = i->d) for (node *j = i->r; J! = i; j = j->r) j->u-> D = J->d->u = J;c->l->r = C->r->l = C;} BOOL DLX () {Node *c = head->r;if (c = = head) return true;if (!remove (c)) return false;for (node *i = c->d; I! = C; i = I->d) {for (node *j = i->r; J! = i; j = j->r) Remove (J->col), if (DLX ()) {printf ("%d", i->x), return true;} for (Node *j = i->r; J! = i; j = j-&Gt R) Recover (j->col);} return false;}  int main () {head = new node (); scanf ("%d%d", &n, &m); for (int i = 1; I <= m; i++) tail[i] = new node (); for (int i = 2; I < m; i++) Tail[i]->l = tail[i-1], Tail[i]->r = tail[i + 1];for (int i = 1; I <= m; i++) Tail[i]->u = Tail[i]->d = Tail[i];head->l = Tail[m], Head->r = tail[1], head->d = Head->u = Head;tail[m]->l = Tail[m-1], tail[m]- >r = Head;tail[1]->r = tail[2], tail[1]->l = head;for (int i = 1; I <= n; i++) {Node *last = null;for (int j = 1; J <= M; J + +) {int a;scanf ("%d", &a), if (a) {node *newnode = new node (null, NULL, TAIL[J], tail[j]->d, tail[j]->d, i); tail [j]->d = Tail[j]->d->u = Newnode;tail[j] = newnode;if (!last) newnode->l = Newnode->r = Newnode;else{newnod E->l = last, Newnode->r = Last->r;last->r = Last->r->l = NewNode;} last = NewNode;}}} if (! DLX ()) printf ("No solution!\n"); return 0;}
        Because of the peculiar code style, the code is a bit wide, please do not spray ...

        Dance Chain (Dancing links) C + + implementation (pointer version)

        Related Article

        Contact Us

        The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

        If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

        A Free Trial That Lets You Build Big!

        Start building with 50+ products and up to 12 months usage for Elastic Compute Service

        • Sales Support

          1 on 1 presale consultation

        • After-Sales Support

          24/7 Technical Support 6 Free Tickets per Quarter Faster Response

        • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.