数独计算
本质还是利用简单的暴力枚举出所有的可能,其中用unsigned link_buf[3][9];来记录行(0) 列(1) 块(2)上可能出现的值.如果要确定某个点(i,j)上可以有的选项就可以用AndValues(link_buf,i,j)将三个取并集
#include <stdio.h>
typedef unsigned Array9x9[9][9];
#define AndValues(link_buf,i,j) \
(RowValues(link_buf,i)&ColumnValues(link_buf,j)&BlockValues(link_buf,i,j))
#define RowValues(link_buf,i) \
(link_buf[0][(i)])
#define ColumnValues(link_buf,j) \
(link_buf[1][(j)])
#define BlockValues(link_buf,i,j) \
(link_buf[2][(i)/3*3+(j)/3])
例如 某点上面可以填写 1 2 4 那么用 (1<<1)|(1<<2))|(1<<4>) 即 10110来表示这上面能取124四个值,利用& |来添加去除或求并集.
回溯方法:
/**
**/
bool cal(int index,Array9x9 data,unsigned link_buf[3][9]){
int i=index/9;
int j=index%9;
while(data[i][j]!=0){
index++;
if(index==81)
return true; //解得
i=index/9;
j=index%9;
}
//因为最小位的设置是1<<1=2所以除以2去掉没有标示值的权位。
unsigned values = AndValues(link_buf,i,j)/2;
if(values){
int value = 1;
while(values){
if(values%2==1){
//设置行列块的可能去除一位
RowValues(link_buf,i) &= ~(1<<value);
ColumnValues(link_buf,j) &= ~(1<<value);
BlockValues(link_buf,i,j) &= ~(1<<value);
//设置 data[i][j] 进入下一层的枚举
data[i][j] = value;
if(cal(index,data,link_buf))
return true; //如果不希望只求单解,则不要返回true
//取消 data[i][j]的值的设置
data[i][j] = 0;
//设置行列块恢复一位
RowValues(link_buf,i) |= (1<<value);
ColumnValues(link_buf,j) |= (1<<value);
BlockValues(link_buf,i,j) |= (1<<value);
}
value++;
values/=2;
}
}
return false;
}
完整代码如下:
#include <stdio.h>
typedef unsigned Array9x9[9][9];
#define AndValues(link_buf,i,j) \
(RowValues(link_buf,i)&ColumnValues(link_buf,j)&BlockValues(link_buf,i,j))
#define RowValues(link_buf,i) \
(link_buf[0][(i)])
#define ColumnValues(link_buf,j) \
(link_buf[1][(j)])
#define BlockValues(link_buf,i,j) \
(link_buf[2][(i)/3*3+(j)/3])
bool cal(int index,Array9x9 data,unsigned link_buf[3][9]){
int i=index/9;
int j=index%9;
while(data[i][j]!=0){
index++;
if(index==81)
return true;
i=index/9;
j=index%9;
}
unsigned values = AndValues(link_buf,i,j)/2;
if(values){
int value = 1;
while(values){
if(values%2==1){
RowValues(link_buf,i) &= ~(1<<value);
ColumnValues(link_buf,j) &= ~(1<<value);
BlockValues(link_buf,i,j) &= ~(1<<value);
data[i][j] = value;
if(index==81-1 || cal(index+1,data,link_buf))
return true; //如果不希望只求单解,则不要返回true
data[i][j] = 0;
RowValues(link_buf,i) |= (1<<value);
ColumnValues(link_buf,j) |= (1<<value);
BlockValues(link_buf,i,j) |= (1<<value);
}
value++;
values/=2;
}
}
return false;
}
int main(int argc, char *argv[])
{
Array9x9 data= {
{8,0,0, 0,0,0, 0,0,0},
{0,0,3, 6,0,0, 0,0,0},
{0,7,0, 0,9,0, 2,0,0},
{0,5,0, 0,0,7, 0,0,0},
{0,0,0, 0,4,5, 7,0,0},
{0,0,0, 1,0,0, 0,3,0},
{0,0,1, 0,0,0, 0,6,8},
{0,0,8, 5,0,0, 0,1,0},
{0,9,0, 0,0,0, 4,0,0}
};
unsigned link_buf[3][9];
for(int type=0;type<3;type++){
for(int index=0;index<9;index++){
link_buf[type][index] = 0x3fe;
}
}
for(int i=0;i<9;i++){
for(int j=0;j<9;j++){
if(data[i][j]>0){
link_buf[0][i] &= ~(1<<data[i][j]);
link_buf[1][j] &= ~(1<<data[i][j]);
link_buf[2][i/3*3+j/3] &= ~(1<<data[i][j]);
}
}
}
cal(0,data,link_buf);
for(int i=0;i<9;i++){
for(int j=0;j<9;j++){
printf("%d,", data[i][j]);
}
printf("\n");
}
return 0;
}