#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;
}
之前水平不够,写了一个不加任何优化,直接搜的解数独程序。
现在水平提高,学会如何用双向十字链表优化时间复杂度来解数独游戏,还不能直接使用它,必须将它转化成“精确覆盖模型”。
为什么?
我尝试着写了一个单纯用双向十字链表来解数独游戏的程序,它有优点也有缺点。之前暴搜的那个程序解特别稀疏的数独就会超时,比如:全是空儿的数独。但是单纯用双向十字链表的程序能够解决这样“全是空儿”的数独,但是还不够~对于有些数独,尤其是唯一解的数独,也同样会超时的,比如下面这个很难很难的数独:
800 000 000
003 600 000
070 090 200
050 007 000
000 045 700
000 100 030
001 000 068
008 500 010
090 000 400
上面的数独对于单纯使用双向十字链表的程序就是克星,因为它的解用一种哲学上的思维来说就是:这个问题的解被排在了后面。对的,深度优先搜索都是一直搜到底的,对于有些问题解被“排在后面”的,深度优先搜索就不行了。
到底什么地方还能优化呢?
其实我们在单纯使用双向十字链表而不进行模型转化的时候,我们与以往搜索唯一的不同就在于我们能够直接找到哪些有空儿、哪些没有空儿,但是有一点:我们还是从1到9枚举了每一个数字,然后对于每个数字通过之前打上的标记判断能不能填,虽然只有9个数字,但是这9个数字的枚举是放在递归层次里的,非常费时。
现在我们不仅需要能够直接知道哪些空儿可以填,我们还需要直接知道哪些数字是可以填的,这样可以加快进程~~~
怎样转化成精确覆盖模型?
构造这样的矩阵:
对于第1~81列:
第1列:在(1,1)填了数字
第2列:在(1,2)填了数字
。。。。。。
第n列:。。。。。。
映射:row=(n-1)/9+1,col=(n-1)%9+1,n=9*(row-1)+col
对于第81~162列:
第1列:在第1行填了数字1
第2列:在第2行填了数字2
。。。。。。
第n列:。。。。。。
映射:row=(n-82)/9+1,num=(n-82)%9+1,n=9*(row+8)+num
对于第163~243列:
第1列:在第1列填了数字1
第2列:在第2列填了数字2
。。。。。。
第n列:。。。。。。
映射:col=(n-163)/9+1,col=(n-163)%9+1,n=9*(col+17)+num
对于第244~324列:
第1列:在第1宫填了数字1
第2列:在第1宫填了数字2
。。。。。。
第n列:。。。。。。
映射:grid=(n-244)/9+1,num=(n-244)%9+1,n=9*(grid+26)+num
对于一个给出的矩阵,如果在(x,y)处是3,那么就插入这样一行
它的9*(x-1)+y,9*(x+8)+3,9*(y+17)+3,9*(grid(x,y),26)+num(坐标映射到宫:3*((x-1)/3)+(y-1)/3+1)
以上四列都是1,但是插入行的时候要记录对应行所代表的意义是什么,这样在搜索时就能很轻易得到信息。
如果是空儿,那么就按照上面的方法在对应坐标将1~9依次插入,总共就是4*9=36个节点。
接下来直接解精确覆盖就可以了,通过选的行的编号,可以知道在那个位置填入几,当然这也要预处理一下,我用的方法就是直接将信息放在Data结构体中,当然可能也有公式,我就不推了。
写的有些潦草,不如网上一些大牛写的好。
下面是一个测试样例和结果:
1
800000000
003600000
070090200
050007000
000045700
000100030
001000068
008500010
090000400
812753649
943682175
675491283
154237896
369845721
287169534
521974368
438526917
796318452
时间相当快,可见双向十字链表+精确覆盖模型的解题速度之快。
不过感觉本文还是写挫了,凑合看吧。
使用双向十字链表(或Dancing Links)解数独游戏,布布扣,bubuko.com
原文地址:http://blog.csdn.net/u011537359/article/details/38585345