因为解的过程没有全局状态这种概念,所以不方便使用著名的H>D模板来解。其实因为格子的数量很少,只要做简章的优化就完全不存在问题。即使用穷举法,也能很快算出答案。(某人:不要小看穷举法!!!>_<++)
下次准备考虑生成游戏的算法,难度应该较高。
console工程的代码
// sudoku.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include "conio.h"
/* 为了代码好看^^ */
#define SUCCESS 1
#define FAILED 0
/* 地图类型9*9的char,每个char从0-9,0表示待填 */
typedef char MAPTYPE[9][9];
/* 行数据,同时用作“可能性”数据。如LINETYPE a; 当a[0]为真时表示
当前位置可填1,a[1]为真时表示可填2,以此类推 */
typedef char LINETYPE[9];
/* 测试用地图文本,摘自http://www.game616.com/ */
const char *_map1 = {
"980000005"
"107050000"
"000076809"
"000840000"
"078500200"
"250000008"
"000000052"
"035001070"
"709030000"
};
/* 从地图文本读取生成地图。地图文本是连续的81个asc数字字符串 */
void parse_map(MAPTYPE dest, const char* src)
{
const char *p = src;
for ( int j = 0; j < 9; j++ )
for ( int i = 0; i < 9; i++ )
{
if (*p == ' ') dest[i][j] = 0;
else dest[i][j] = (*p) - '0';
p++;
}
}
/* 打印地图 */
void dump_map(MAPTYPE dest)
{
for ( int j = 0; j < 9; j++ )
{
for ( int i = 0; i < 9; i++ )
{
printf("%d ", dest[i][j]);
}
printf("/n");
}
printf("/n");
}
int fill_line(MAPTYPE dest, int line, MAPTYPE result);
/* 填下一个格子。本行的可能性已在调用前算好,要考虑的是列的可能性和九宫格的可能性 */
/* nums_possible : array (0-8) means possible of number (1-9) */
int fill_pos(MAPTYPE dest, LINETYPE nums_possible, int line, int pos, MAPTYPE result)
{
if ( pos >= 9 ) return SUCCESS;
if ( dest[pos][line] != 0 ) return fill_pos(dest, nums_possible, line, pos + 1, result);
for ( int i = 0; i < 9; i++ )
{
if ( !nums_possible[i] ) continue;
/* 检查本列是否重复 */
int vetical_failed = 0;
for ( int j = 0; j < 9; j++ )
if ( dest[pos][j] == i + 1 )
{
vetical_failed = 1;
break;
}
if ( vetical_failed ) continue;
/* 检查九宫格是否重复 */
int nine_failed = 0;
int m = pos / 3;
int n = line / 3;
m *= 3;
n *= 3;
for ( int y = n; y < n + 3; y++ )
{
for ( int x = m; x < m + 3; x++ )
{
if ( dest[x][y] == i + 1 )
{
nine_failed = 1;
break;
}
}
if ( nine_failed ) break;
}
if ( nine_failed ) continue;
/* all ok, try next position */
dest[pos][line] = i + 1;
nums_possible[i] = 0;
if ( fill_pos(dest, nums_possible, line, pos + 1, result) )
{
/* 本行已全部OK,尝试下一行 */
if ( fill_line(dest, line + 1, result) ) return SUCCESS;
/* 下一行失败,重新尝试本位置的剩余可能性 */
}
nums_possible[i] = 1;
dest[pos][line] = 0;
}
return FAILED;
}
/* 填下一行 */
int fill_line(MAPTYPE dest, int line, MAPTYPE result)
{
if ( line >= 9 )
{
/* copy map */
memcpy(result, dest, sizeof(MAPTYPE));
return SUCCESS;
}
LINETYPE nums;
LINETYPE saveline;
/* calc possibility(for the current line) */
for ( int i = 0; i < 9; i++ ) nums[i] = 1; /* all can be */
for ( int i = 0; i < 9; i++ )
{
char n = dest[i][line];
/* save line */
saveline[i] = dest[i][line];
if ( n != 0 ) nums[n - 1] = 0; /* appears */
}
if ( !fill_pos(dest, nums, line, 0, result) )
{
/* restore line */
for ( int i = 0; i < 9; i++ ) dest[i][line] = saveline[i];
return FAILED;
}
return SUCCESS;
}
int _tmain(int argc, _TCHAR* argv[])
{
MAPTYPE dest, result;
parse_map(dest, _map1);
if ( fill_line(dest, 0, result) ) dump_map(result);
getch();
return 0;
}