/*
============================================================================
Name : sudoku.c
Author : Joey
Version :
Copyright : UESTC
Description : Try to solve sudoku puzzle.
1.0 2010年10月27日20:28:13 Create
1.1 2010-11-9 19:03:22 modify
输入参数:保存数独棋盘格局的文件名
文件的数据是9*9的矩阵,每个数的取值范围为0-9
0表示该位置对应棋盘上的数据位空
1-9代表该位置对应的数
如果不提供输入参数,程序会以交互式的方式请求用户指定一个文件名。
============================================================================
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//#include <time.h>
//#define _DEBUG /*调试开关*/
#define MAX_FILE_NAME_LEN 30 /*文件名字符串最大长度*/
#define BOARD_SIZE 9 /*棋盘大小*/
#define BLOCK_SIZE 3 /*每块区域大小*/
#define VALID_MASK 0x03FE /*倒数第2位至倒数10位为有效标志位*/
/**
* 这些宏定义用于将标志位置位或者清除
*/
#define setblockbit(rowidx,colidx,a) (blockbits[rowidx/3][colidx/3] |= 1<<a)
#define clearblockbit(rowidx, colidx, a) (blockbits[rowidx/3][colidx/3] &= ~(1<<a))
#define testblockbit(rowidx, colidx, a) (blockbits[rowidx/3][colidx/3] & (1<<a) & VALID_MASK)
#define setrowbit(rowidx,a) (rowbits[rowidx] |= 1<<a)
#define clearrowbit(rowidx,a) (rowbits[rowidx] &= ~(1<<a))
#define testrowbit(rowidx, a) (rowbits[rowidx] & (1<<a) &VALID_MASK)
#define setcolumnbit(colidx,a) (columnbits[colidx] |= 1<<a)
#define clearcolumnbit(colidx,a) (columnbits[colidx] &= ~(1<<a))
#define testcolumnbit(colidx,a) (columnbits[colidx] & (1<<a) & VALID_MASK)
/**
* 位置类型
*/
typedef struct Coodinate_T{
int row;
int column;
}Coordinate;
typedef struct Stkelemnt_T{
int idx;
int number;
}Stkelement;
int board[BOARD_SIZE][BOARD_SIZE];/*保存棋盘数据*/
unsigned short blockbits[BLOCK_SIZE][BLOCK_SIZE];/*保存9个3*3方块的数据状态*/
unsigned short rowbits[BOARD_SIZE]; /*保存每一行数据状态*/
unsigned short columnbits[BOARD_SIZE]; /*保存每一列的数据状态*/
Coordinate blanklist[BOARD_SIZE*BOARD_SIZE]; /*保存了待填写等方格位置*/
int blanknum = 0; /*待填写方格总个数*/
/************************************/
/* Internal struct for DFS algorithm*/
Stkelement stk[300];
int top = 0;
/***********************************/
void trysolve(FILE *fp);
int loadAndCheckInitBoard(FILE *fp);
int searchAns(int row, int column, int from);
int solve();
void pushstk(int blankidx, int num);
Stkelement popstk();
void outputresult();
#ifdef _DEBUG
void printstk();
#endif
/**
*程序入口,第一个运行参数为输入文件文件名,若不存在,从控制台中交互获取文件名
*/
int main(int argc, char** argv) {
char filename[MAX_FILE_NAME_LEN];
FILE *fp = NULL;
if (argc <= 1){
printf("input file name:");
scanf("%s",filename);
}else{
strcpy(filename, argv[1]);
}
fp = fopen(filename,"r");
if (fp == NULL){
fprintf(stderr,"Error occurred when open file %s", filename);
exit(EXIT_FAILURE);
}
trysolve(fp);
fclose(fp);
return EXIT_SUCCESS;
}
/**
* 输入:
* row:格子的行
* column:格子的列
* from:从该数开始递增查找
* 输出:返回值为
* 0:未找到
* 1-9:找到的可行解
*/
int searchAns(int row, int column, int from){
int number = from;
if (number > 9 || number < 1){ //起始值过大或过小
return 0;
}
while (number <= 9){
if (testblockbit(row, column, number)==0
&& testrowbit(row, number)==0
&& testcolumnbit(column, number)==0){
return number;
}else
number++;
}
return 0; /*未找到*/
}
/**
* 从fp指向的文件中读取初始棋盘,尝试解决数独问题
*/
void trysolve(FILE *fp){
int rt = loadAndCheckInitBoard(fp);
if (1 == rt){
printf("Initial board isn't correct!\n");
}else if (2 == rt ){
printf("Invalid data was contented in the file!\n");
}else if (3== rt){
printf("数据不完整\n");
}else{
printf("Load board successfully, try to solve...\n");
if (solve() == 0){
printf("Success, result:\n");
outputresult();
}else{
printf("The puzzle can't be solved\n");
}
}
return;
}
/**
* 加载初始棋盘并对数独棋盘的可解性做初步检查,棋盘有效数据为0-9,大小为9*9
* fp:
* 已打开的文件指针
* 返回值:
* 0:成功读取9*9棋盘
* 1:初始棋盘不合规则
* 2:文件中包含无效数据
* 3:数据不完整
*/
int loadAndCheckInitBoard(FILE *fp){
int a;
int idx = 0;
int rowidx = 0;
int columnidx = 0;
Coordinate cood;
while(fscanf(fp, "%d", &a) != EOF){
rowidx = idx / 9; /*行数*/
columnidx = idx % 9; /*列数*/
if (a >= 1 && a <= 9){ /*如果是已填格子*/
if (testblockbit(rowidx,columnidx,a) == 0
&& testcolumnbit(columnidx,a) == 0
&& testrowbit(rowidx, a) == 0){
setblockbit(rowidx, columnidx, a);
setrowbit(rowidx, a);
setcolumnbit(columnidx, a);
}else{
return 1; /*初始棋盘本身有错*/
}
}else if (a == 0){ /*如果是待填格子,记录下待填格子的坐标*/
cood.row = rowidx;
cood.column = columnidx;
blanklist[blanknum++] = cood;
}else{
return 2; /*发现无效数据*/
}
board[rowidx][columnidx] = a;
idx++;
}
/*数据不够,格式错误*/
if (idx != BOARD_SIZE * BOARD_SIZE){
return 3;
}
return 0; /*加载成功*/
}
/**
* 递归求解数独问题,调用前初始数据已被正确读取,
* 返回值:
* 0:找到一个可行解
* 1:未找到可行解
*/
int solve(){
int fillidx = 0; /*fill index in blanklist*/
int ans = 0;
Stkelement curcell;
pushstk(fillidx, ans); /*初始入栈的值*/
while (top != 0){ /*栈不为空*/
#ifdef _DEBUG
printstk();
#endif
curcell = popstk();
ans = curcell.number;
fillidx = curcell.idx;
ans = searchAns(blanklist[fillidx].row, blanklist[fillidx].column,
ans+1);
while(ans != 0){
pushstk(fillidx, ans);
#ifdef _DEBUG
printstk();
#endif
if (fillidx == blanknum-1){
return 0; /*找到了一个可行解*/
}
fillidx++;
ans = searchAns(blanklist[fillidx].row, blanklist[fillidx].column,
1);
}
}
return 1; /*无解*/
}
/**
* 将blankidx对应的坐标压入栈中,并根据该位置上的数字将相应的bit置位
*/
void pushstk(int blankidx, int num){
/*set bits*/
setblockbit(blanklist[blankidx].row, blanklist[blankidx].column, num);
setrowbit(blanklist[blankidx].row, num);
setcolumnbit(blanklist[blankidx].column, num);
/*push into stack*/
Stkelement ele = {blankidx, num};
stk[top++] = ele;
return ;
}
/**
* 弹出栈顶的元素,并将该元素对应的bit清楚
*/
Stkelement popstk(){
Stkelement ele = stk[--top];
/*clear bits*/
clearblockbit(blanklist[ele.idx].row, blanklist[ele.idx].column, ele.number);
clearrowbit(blanklist[ele.idx].row, ele.number);
clearcolumnbit(blanklist[ele.idx].column, ele.number);
/**/
return ele;
}
#ifdef _DEBUG
void printstk(){
int i = top-1;
printf("***********Stack trace************\n");
for (;i >= 0; i--){
printf("%dth row:%d column:%d number:%d\n",
i, blanklist[stk[i].idx].row, blanklist[stk[i].idx].column,
stk[i].number);
}
printf("**********************************\n");
fflush(stdout);
}
#endif
/**
* 输出结果至标准输出设备
*/
void outputresult(){
int r,c;
int i = 0;
for (;i < top; i++){
board[blanklist[stk[i].idx].row][blanklist[stk[i].idx].column]
= stk[i].number;
}
for (r = 0; r < BOARD_SIZE; r++){
for (c = 0; c < BOARD_SIZE; c++){
printf("%d ",board[r][c]);
}
printf("\n");
}
fflush(stdout);
}
Python版的
#coding=utf-8
'''
Created on 2011-11-29
解决8皇后问题
广搜算法
@author: Joey
'''
import copy
def solve():
queue = []
for i in range(8):
queue.append([(0,i)])
results = []
max = 0
while len(queue) > 0:
poslist = queue.pop(0)
lastrow = poslist[-1][0]
assert lastrow < 7
for col in range(0,8):
if islegal((lastrow+1,col), poslist):
poslstcpy = copy.deepcopy(poslist)
poslstcpy.append((lastrow+1,col))
if len(poslstcpy) == 8:
results.append(poslstcpy)
else:
queue.append(poslstcpy)
if len(queue) > max: max = len(queue)
print max
print len(results)
for item in results:
printresul(item)
def islegal(pos, poslist):
for xpos in poslist:
if xpos[0] == pos[0] or xpos[1] == pos[1] \
or abs(xpos[0]-pos[0]) == abs(xpos[1]-pos[1]):
return False
return True
def printresul(poslist):
for row in range(8):
for col in range(8):
if (row,col) in poslist:
print 'o',
else:
print '.',
print ' '
print '--------'
solve()