正文

数独计算器2006-12-06 23:02:00

【评论】 【打印】 【字体: 】 本文链接:http://blog.pfan.cn/goal00001111/21343.html

分享到:

前一段时间写的数独计算器,由于代码太长,这里只贴出算法思路和用到的功能函数,以及主函数.有感兴趣的可以向我索要完整的源代码.

/*
  Name: 数独
  Copyright: 自由软件
  Author: goal00001111
  Date: 02-12-06 17:00
  Description: 版本号3.0 对2.0版本进行了优化,使输出更合理,并能输出多个解
  算法思想:1。利用不重复原理(即每个数字在每行,列,小九宫中只能出现一次),根据已确定位置,
  排除与其同行,同列和同小九宫位置不能取的值。
  2。根据完备性原理(即每个数字在每行,列,小九宫中必须出现一次),
  若某个数字只能在某行,列,小九宫中的一个位置出现,则该位置的确定值就为该数字。
  3。根据双隐数对方法,即同一行,列,小九宫中,若有两个位置都有且仅有两个相同的可能值,
  则同一行,列,小九宫中的其他位置不能取该两个值。或在同一行,列,小九宫中,若某两个数字
  存且仅存在于两个位置中,则这两个位置只可能取这两个值。
  4。经过上面三个步骤以后,一般的数独题目都可以解决了。
  若通过前面三种方法还不能确定全部位置,则调用杀手锏---穷举法。
  因为经过前面三个步骤以后,未知位置已经不多了,而且未知位置的可能值也不多了,这时候只要
  猜中某一个位置,则可能得到答案。
  因此可以遍历所有未知位置,穷举某一个(注意不是每一个)位置的可能值,再由它得到其他位置的值,
  如果出错或不能得到最终结果(确定全部位置),则分析下一个位置。
  注意:这里不是采用回溯的方法----因为回溯所需空间太大,而是利用只要猜中某一个位置,
  则可得到答案的原理,遍历所有未知位置。这样只需要一个辅助空间,花费很小。
*/ 
#include <cstdlib>
#include <iostream>
#include <fstream>

using namespace std;

const int N = 9;
const int POSSIBLE = 1;  //表示九宫格中的位置可以某个值
const int IMPOSSIBLE = 0; //表示九宫格中的位置不可以某个值
const bool GUESS = false; //猜测模式
const bool REALITY = true; //实际模式

struct NODE{
 int data[N+1]; //数组的下标对应1-9,data[k]可以取值POSSIBLE或IMPOSSIBLE
 bool only; //表示该位置的值是否确定
} ;

void Input(struct NODE lib[][N]); //输入初试数据
void ShowBlock(const struct NODE lib[][N]); //输出九宫格
bool IsWrongLib(const struct NODE lib[][N], int & x, int & y);//判断是否输入了错误的数据

int BasicMeans(struct NODE lib[][N]); //使用基本方法解题,并返回需要的步数

void Build(struct NODE lib[][N]); //根据输入的数据,初步排除每个位置不可能的取值
void TheSameRow(struct NODE lib[][N], int row, int cel); //根据同一行的已知数据排除该位置不可能的取值
void TheSameCel(struct NODE lib[][N], int row, int cel); //根据同一列的已知数据排除该位置不可能的取值
void TheSameBlock(struct NODE lib[][N], int row, int cel); //根据同一小九宫格的已知数据排除该位置不可能的取值

int ChooseOnly(struct NODE lib[][N], int & count, bool mode); //把根据推导得到的新的确定位置值添加到九宫格中,若没有确定新位置,则返回0
bool IsOnly(int pos[], int & num); //判断该位置的值是否唯一
//判断同行,列,小九宫中是否有n相同的值 
bool IsRepeated(const struct NODE lib[][N], int row, int cel, int n);

int AnalyseNumber(struct NODE lib[][N], int & count, bool mode); //遍历数字1-9,进一步确定每个位置可能的取值
//累积每行中可以取值为n的位置的个数,如果只有一个位置可以取值为n,则可以断定该位置的值只能为n
int JudgeRow(struct NODE lib[][N], int n, int & count, bool mode);
//累积每列中可以取值为n的位置的个数,如果只有一个位置可以取值为n,则可以断定该位置的值只能为n
int JudgeCel(struct NODE lib[][N], int n, int & count, bool mode);
//累积每个小九宫格中可以取值为n的位置的个数,如果只有一个位置可以取值为n,则可以断定该位置的值只能为n
int JudgeBlock(struct NODE lib[][N], int n, int & count, bool mode);

bool DoubleNumble(struct NODE lib[][N], bool mode);//处理双隐数对
//处理某一行的双隐数对:该行有两个位置有且仅有两个相同的值
bool RowJudgeByPosition(struct NODE lib[][N], int store[][N+1], int row, bool mode);
//处理某一行的双隐数对:该行有两个数字存在且仅存在于两个位置中
bool RowJudgeByNumber(struct NODE lib[][N], int store[][N+1], int row, bool mode);
//处理某一列的双隐数对:该列有两个位置有且仅有两个相同的值
bool CelJudgeByPosition(struct NODE lib[][N], int store[][N+1], int cel, bool mode);
//处理某一列的双隐数对:该列有两个数字存在且仅存在于两个位置中
bool CelJudgeByNumber(struct NODE lib[][N], int store[][N+1], int cel, bool mode);
//处理某一小九宫格的双隐数对:该小九宫格有两个数字存在且仅存在于两个位置中
bool BlockJudgeByNumber(struct NODE lib[][N], int store[][N+1], int row, int cel, bool mode);
//处理某一小九宫格的双隐数对:该小九宫格有两个位置有且仅有两个相同的值
bool BlockJudgeByPosition(struct NODE lib[][N], int store[][N+1], int row, int cel, bool mode);

//处理与双隐数对处在同一行的其他位置
void DoTheRow(struct NODE lib[][N], int row, int cel_1, int cel_2);
//处理与双隐数对处在同一列的其他位置
void DoTheCel(struct NODE lib[][N], int cel, int row_1, int row_2);
//处理与双隐数对处在同一小九宫格的其他位置
void DoTheBlock(struct NODE lib[][N], int row, int cel, int row_1, int cel_1, int row_2, int cel_2);

bool IsTwo(const struct NODE lib[][N], int row, int cel);//判断该位置是否只有两个可能值
bool Equal(const struct NODE & a, const struct NODE & b);//判断两个位置的可能值是否相等
int BlockPosition(int row, int cel);//获取小九宫格的序号

bool IsEnd(const struct NODE lib[][N]); //已经得到正确结果

void Guess(const struct NODE lib[][N], int step);//使用穷举法进行猜测,以得到一个可能的答案
void CopyData(struct NODE to[][N], const struct NODE from[][N]);//复制九宫格数据到一个临时数组
void AddToLib(struct NODE lib[][N], int x, int y, int n);//把猜测的位置放到九宫格中
bool GetAnswer(struct NODE lib[][N], int & step, bool mode);//判断猜测是否正确,若正确则输出该结果
void ShowProcess(const struct NODE lib[][N], int x, int y, int n, int & step, bool getOne);//演示得到正确结果的步骤

int main(int argc, char *argv[])
{
 struct NODE lib[N][N]; //存储九宫格所有数据
 
 Input(lib); //输入初试数据
 ShowBlock(lib); //输出九宫格
 
 int x, y;
 if (IsWrongLib(lib, x, y))//判断是否输入了错误的数据
 {
  cout << "(" << x << "," << y << ")重复"<< endl;
  system("pause");
  return 0;
 }
 
 Build(lib); //根据输入的数据,初步排除每个位置不可能的取值
 
 int count = BasicMeans(lib);//使用基本方法解题,并返回需要的步数 
 if (count == -1)
 {
  cout << "无解" << endl;
  system("pause");
  return 0;
 }
 
 if (!IsEnd(lib)) //如果基本方法不能确定全部位置,则调用杀手锏---穷举法
  Guess(lib, count);
 else
 {
  ShowBlock(lib); //输出九宫格
  cout << "共需要" << count << "步 " << endl;
 }
 
 cout << "花了" << clock() << "毫秒 " << endl;
 
    system("PAUSE");
    return EXIT_SUCCESS;
}

阅读(10359) | 评论(18)


版权声明:编程爱好者网站为此博客服务提供商,如本文牵涉到版权问题,编程爱好者网站不承担相关责任,如有版权问题请直接与本文作者联系解决。谢谢!

评论

loading...
您需要登录后才能评论,请 登录 或者 注册