Use a two-way cross-linked list (or dancing links) to solve a Sudoku game

Source: Internet
Author: User
#include<stdio.h>#include<string.h>#include<algorithm>using namespace std;struct Data{    void assign(int x,int y,int z)    {        row=x;        col=y;        val=z;    }    int row,col,val;} data[730];struct Node{    Node(int x=0,int y=0):        row(x),col(y),up(this),down(this),left(this),right(this) {}    int row,col;    Node *up,*down,*left,*right;}**rowHead,**colHead;char tempData[9][10];int rowCounter[730],colCounter[325];int ans[10][10];int belong[10][10],belong1[10][10],belong2[10][10],belong3[10][10],belong4[10][10];int belongX[325],belongY[325];void init(){    rowHead=new Node*[730],colHead=new Node*[325];    for(int i=0; i<=729; i++)rowHead[i]=new Node(i,0);    for(int i=0; i<=324; i++)colHead[i]=new Node(0,i);    for(int i=0; i<=729; i++)        if(i&&i!=729)        {            rowHead[i]->up=rowHead[i-1];            rowHead[i]->down=rowHead[i+1];        }        else if(!i)        {            rowHead[i]->up=rowHead[729];            rowHead[i]->down=rowHead[i+1];        }        else        {            rowHead[i]->up=rowHead[i-1];            rowHead[i]->down=rowHead[0];        }    for(int i=0; i<=324; i++)        if(i&&i!=324)        {            colHead[i]->left=colHead[i-1];            colHead[i]->right=colHead[i+1];        }        else if(!i)        {            colHead[i]->left=colHead[324];            colHead[i]->right=colHead[i+1];        }        else        {            colHead[i]->left=colHead[i-1];            colHead[i]->right=colHead[0];        }    memset(rowCounter,0,sizeof(rowCounter));    memset(colCounter,0,sizeof(colCounter));    memset(ans,0,sizeof(ans));}void link(int x,int y){    Node *newNode=new Node(x,y);    if(rowHead[x]->right==rowHead[x])    {        newNode->left=newNode->right=rowHead[x];        rowHead[x]->left=rowHead[x]->right=newNode;        rowCounter[x]++;    }    else    {        for(Node *i=rowHead[x]->right;; i=i->right)            if(newNode->col<i->col||!i->col)            {                newNode->left=i->left;                newNode->right=i;                i->left->right=newNode;                i->left=newNode;                rowCounter[x]++;                break;            }    }    if(colHead[y]->down==colHead[y])    {        newNode->up=newNode->down=colHead[y];        colHead[y]->up=colHead[y]->down=newNode;        colCounter[y]++;    }    else    {        for(Node *i=colHead[y]->down;; i=i->down)            if(newNode->row<i->row||!i->row)            {                newNode->up=i->up;                newNode->down=i;                i->up->down=newNode;                i->up=newNode;                colCounter[y]++;                break;            }    }}void remove(Node *&x){    x->left->right=x->right,x->right->left=x->left;    for(Node *i=x->down; i!=x; i=i->down)        for(Node *j=i->right; j!=i; j=j->right)            if(j!=rowHead[i->row])            {                j->up->down=j->down;                j->down->up=j->up;                colCounter[j->col]--;            }}void resume(Node *&x){    for(Node *i=x->up; i!=x; i=i->up)        for(Node *j=i->left; j!=i; j=j->left)            if(j!=rowHead[i->row])            {                colCounter[j->col]++;                j->down->up=j;                j->up->down=j;            }    x->right->left=x,x->left->right=x;}bool dance(){    if(colHead[0]->right==colHead[0])return true;    int best=2147483647;    Node *bestNode;    for(Node *i=colHead[0]->right; i!=colHead[0]; i=i->right)        if(best>colCounter[i->col])        {            best=colCounter[i->col];            bestNode=i;        }    remove(bestNode);    for(Node *i=bestNode->down; i!=bestNode; i=i->down)    {        ans[data[i->row].row][data[i->row].col]=data[i->row].val;        for(Node *j=i->right;j!=i;j=j->right)            if(j!=rowHead[i->row])                remove(colHead[j->col]);        if(dance())return true;        for(Node *j=i->left;j!=i;j=j->left)            if(j!=rowHead[i->row])                resume(colHead[j->col]);    }    resume(bestNode);    return false;}int main(){    for(int i=1; i<=9; i++)        for(int j=1; j<=9; j++)            belong[i][j]=3*((i-1)/3)+(j-1)/3+1,                         belong1[i][j]=9*(i-1)+j,                                       belong2[i][j]=9*(i+8)+j,                                               belong3[i][j]=9*(i+17)+j,                                                       belong4[i][j]=9*(i+26)+j;    for(int i=1; i<=81; i++)        belongX[i]=(i-1)/9+1,                   belongY[i]=(i-1)%9+1;    for(int i=82; i<=162; i++)        belongX[i]=(i-82)/9+1,                   belongY[i]=(i-82)%9+1;    for(int i=163; i<=243; i++)        belongX[i]=(i-163)/9+1,                   belongY[i]=(i-163)%9+1;    for(int i=244; i<=324; i++)        belongX[i]=(i-244)/9+1,                   belongY[i]=(i-244)%9+1;    int T;    scanf("%d",&T);    getchar();    for(int countT=1; countT<=T; countT++)    {        init();        int countRow=0;        for(int i=0; i<9; i++)        {            gets(tempData[i]);            for(int j=0; j<9; j++)                if(tempData[i][j]!='0')                {                    int tempNumber=tempData[i][j]-'0';                    countRow++;                    data[countRow].assign(i+1,j+1,tempNumber);                    link(countRow,belong1[i+1][j+1]);                    link(countRow,belong2[i+1][tempNumber]);                    link(countRow,belong3[j+1][tempNumber]);                    link(countRow,belong4[belong[i+1][j+1]][tempNumber]);                }                else                {                    int counter=9,tempNumber=1;                    while(counter--)                    {                        countRow++;                        data[countRow].assign(i+1,j+1,tempNumber);                        link(countRow,belong1[i+1][j+1]);                        link(countRow,belong2[i+1][tempNumber]);                        link(countRow,belong3[j+1][tempNumber]);                        link(countRow,belong4[belong[i+1][j+1]][tempNumber]);                        tempNumber++;                    }                }        }        if(dance())        {            for(int i=1; i<=9; i++)            {                for(int j=1; j<=9; j++)printf("%d",ans[i][j]);                putchar('\n');            }        }    }    return 0;}


If the previous level is not enough, I wrote a program for solving the sudoku without any optimization.

Now we can improve the level and learn how to use a two-way cross-linked list to optimize the time complexity to solve the sudoku game. Instead of using it directly, we must convert it into a "precise coverage model ".

Why?

I tried to write a program that simply uses a two-way cross-linked list to solve the sudoku game. It has advantages and disadvantages. The program used for brute-force search will time out when it solves a particularly sparse data-independence problem. For example, it is all empty data-independence. However, simply using a two-way cross-linked list program can solve the problem of "being empty", but it is not enough ~ Some Sudoku, especially those with the unique solution, also times out. For example, the following is a hard-to-use Sudoku:

800 000

003 600 000

070 090 200

050 007 000

000 045 700

100 030

001 000 068

008 500 010

090 000 400

The above process of using a two-way cross-linked list is a K-star, because its solution is philosophical: the solution to this problem is placed behind. Yes, the deep-priority search is always the final search. If some problems are solved "behind", the deep-priority search will not work.

Where can we optimize it?

In fact, when we simply use a two-way cross linked list instead of model conversion, the only difference between us and the previous search is that we can directly find what is empty and what is empty, but there is one thing: we enumerate each number from 1 to 9, and then use the previous mark for each number to determine whether it can be filled. Although there are only nine numbers, however, the enumeration of the nine numbers is placed in a recursive hierarchy, which is very time-consuming.

Now we not only need to know which blank space can be entered, but also need to know which numbers can be entered directly, so as to speed up the process ~~~

How to convert it into a precise coverage model?


Construct a matrix like this:


For 1st ~ 81 columns:

Column 1st: enter a number in ()

Column 2nd: enter a number in (1, 2 ).

......

Column N :......

Ing: ROW = (n-1)/9 + 1, Col = (n-1) % 9 + 1, n = 9 * (Row-1) + col


For 81st ~ Columns 162:

Column 1st: Enter the number 1 in row 1st.

Column 2nd: Number 2 is entered in row 2nd.

......

Column N :......

Ing: ROW = (n-82)/9 + 1, num = (n-82) % 9 + 1, n = 9 * (row + 8) + num


For 163rd ~ Columns 243:

Column 1st: Enter the number 1 in column 1st.

Column 2nd: Enter the number 2 in Column 2nd.

......

Column N :......

Ing: Col = (n-163)/9 + 1, Col = (n-163) % 9 + 1, n = 9 * (COL + 17) + num


For 244th ~ Columns 324:

Column 1st: Enter the number 1 in section 1st.

Column 2nd: Enter the number 2 in section 1st.

......

Column N :......

Ing: Grid = (n-244)/9 + 1, num = (n-244) % 9 + 1, n = 9 * (grid + 26) + num


For a given matrix, if it is 3 at (x, y), insert such a row.

It's 9 * (x-1) + Y, 9 * (x + 8) + 3, 9 * (Y + 17) + 3, 9 * (grid (x, y), 26) + num (coordinate ing to palace: 3 * (x-1)/3) + (Y-1)/3 + 1)

The above four columns are all 1, but the meaning of the corresponding row must be recorded when the row is inserted, so that information can be easily obtained during search.


If it is empty, then according to the above method in the corresponding coordinate will 1 ~ 9 is inserted in sequence, which is 4*9 = 36 nodes in total.


Next, you can solve the exact overwrite operation. by specifying the number of the selected row, you can know the number of rows to be filled in. Of course, this also requires preprocessing, the method I used is to directly put the information in the data structure. Of course, there may also be formulas, so I will not push them.


It is not as good as writing something scrawled on the Internet.

The following is a test example and result:

1
800000000
003600000
070090200
050007000
000045700
000100030
001000068
008500010
090000400


812753649
943682175
675491283
154237896
369845721
287169534
521974368
438526917
796318452

The time is quite fast. It can be seen that the speed of solving the problem of Bidirectional cross linked list + precise coverage model is very fast.

However, I still feel frustrated in this article. Let's take a look.




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.