mstc面试题-数独
2006-10-14 15:27 老博客哈 阅读(1563) 评论(1) 编辑 收藏 举报前几天学校的mstc招新,没事凑个热闹,跑过去拿了一份笔试题目。
题目其实就是一个数独(sudoku)游戏的简化版本,关于数独大家可以去看看
这篇介绍http://sudoku.chuchuang.net/
大体意思就是给定一个9*9的矩阵,初始时候里面有了一些1~9数字,
现在要求往矩阵中填入1~9的数字, 使得每行每列的数字不重复
9 0 5 8 0 4 0 2 0
8 0 0 1 0 5 0 0 9
1 0 0 0 0 0 5 0 3
0 0 0 3 9 0 8 0 0
2 0 8 0 0 0 7 0 1
3 0 9 0 8 1 0 0 0
5 0 4 0 0 0 0 1 0
7 0 0 6 0 0 0 0 0
0 8 0 5 0 3 9 0 0
初始矩阵如上.
好了, 附上我的以行为单位的回溯解法(注意:解不止一组,这里给出一组解就可以了)
/*
算法思想: 这个算法题目是一个简化的数独问题。我采用的是比较经典的回溯方法,类似九皇后(排除
斜线的规则)。以行为单位向矩阵中逐个的插入n(n从1到NUM),当然前提是该位置不存在数,且若放置该数
不会造成冲突,这里冲突的定义是行列存在相同的值。如果存在冲突,则相应的找到正在插入的行上面的具有
非初始值n的行,并进行回溯操作。
Author: 农夫三拳(drizzlecrj@gmail.com)
*/
#include <iostream>
#include <fstream>
using namespace std;
const int NUM = 9; //矩阵的行数
int cube[NUM][NUM]; //矩阵的初始排布
int Routine[NUM + 1][NUM]; //对应每一个数字n在每行上的下标数组
//判断该行是否已经存在数字num,r代表行号
bool IsExistInRow(int r,int num)
{
for(int j = 0; j < NUM; j++)
{
if(cube[r][j] == num)
return true;
}
return false;
}
//判断该列是否存在数字num,c代表列号
bool IsExistInColumn(int c,int num)
{
for(int i = 0; i < NUM; i++)
{
if(cube[i][c] == num)
return true;
}
return false;
}
//从文件初始读入矩阵并初始化Routine数组
void Initialize()
{
ifstream fin("input.txt");
int i, j;
for(i = 0; i < NUM; i++)
{
for(j = 0; j < NUM; j++)
{
fin >> cube[i][j];
}
}
for(i = 1; i <= NUM; i++)
{
for(j = 0; j < NUM; j++)
{
Routine[i][j] = -1;
}
}
}
//打印矩阵
void Print()
{
int i, j;
for(i = 0; i < NUM; i++)
{
for(j = 0; j < NUM - 1; j++)
{
cout << cube[i][j] << ' ';
}
cout << cube[i][j] << endl;
}
}
//核心函数,向矩阵中插入数字n
bool FillNum(int n)
{
if( n > NUM)
return true;
int i, j;
i = j = 0;
while(true)
{
if(i == NUM)
{
if(FillNum(n + 1)) //填取下一个数字
break;
else
{
goto loop;
}
}
while(i < NUM && IsExistInRow(i, n))//判断i行是否存在该数
i++;
//如果该行不存在待添加的数字,才进行下面的列检查
if(i < NUM)
{
while((j < NUM && IsExistInColumn(j, n)) || cube[i][j] != 0)//判断j列是否存在该数
j++;
//如果该列不存在待添加的数字,进行记录操作(包括记录Routine,填充矩阵)
if(j < NUM)
cube[i][j] = n, Routine[n][i] = j,++i, j = 0;
else
{
loop:
while(i >= 1 && Routine[n][i-1] == -1)//向上找到初始不存在的该数行号
i--;
//进行回溯操作
if( i >= 1)
{
cube[i - 1][ Routine[n][i - 1] ] = 0;
j = Routine[n][i - 1] + 1;
Routine[n][i - 1] = -1;
i--;
}
else if(i <= 0)
{
return false;
}
}
}
}
return true;
}
int main()
{
Initialize();
FillNum(1);
Print();
cin.ignore();
return 0;
}
算法思想: 这个算法题目是一个简化的数独问题。我采用的是比较经典的回溯方法,类似九皇后(排除
斜线的规则)。以行为单位向矩阵中逐个的插入n(n从1到NUM),当然前提是该位置不存在数,且若放置该数
不会造成冲突,这里冲突的定义是行列存在相同的值。如果存在冲突,则相应的找到正在插入的行上面的具有
非初始值n的行,并进行回溯操作。
Author: 农夫三拳(drizzlecrj@gmail.com)
*/
#include <iostream>
#include <fstream>
using namespace std;
const int NUM = 9; //矩阵的行数
int cube[NUM][NUM]; //矩阵的初始排布
int Routine[NUM + 1][NUM]; //对应每一个数字n在每行上的下标数组
//判断该行是否已经存在数字num,r代表行号
bool IsExistInRow(int r,int num)
{
for(int j = 0; j < NUM; j++)
{
if(cube[r][j] == num)
return true;
}
return false;
}
//判断该列是否存在数字num,c代表列号
bool IsExistInColumn(int c,int num)
{
for(int i = 0; i < NUM; i++)
{
if(cube[i][c] == num)
return true;
}
return false;
}
//从文件初始读入矩阵并初始化Routine数组
void Initialize()
{
ifstream fin("input.txt");
int i, j;
for(i = 0; i < NUM; i++)
{
for(j = 0; j < NUM; j++)
{
fin >> cube[i][j];
}
}
for(i = 1; i <= NUM; i++)
{
for(j = 0; j < NUM; j++)
{
Routine[i][j] = -1;
}
}
}
//打印矩阵
void Print()
{
int i, j;
for(i = 0; i < NUM; i++)
{
for(j = 0; j < NUM - 1; j++)
{
cout << cube[i][j] << ' ';
}
cout << cube[i][j] << endl;
}
}
//核心函数,向矩阵中插入数字n
bool FillNum(int n)
{
if( n > NUM)
return true;
int i, j;
i = j = 0;
while(true)
{
if(i == NUM)
{
if(FillNum(n + 1)) //填取下一个数字
break;
else
{
goto loop;
}
}
while(i < NUM && IsExistInRow(i, n))//判断i行是否存在该数
i++;
//如果该行不存在待添加的数字,才进行下面的列检查
if(i < NUM)
{
while((j < NUM && IsExistInColumn(j, n)) || cube[i][j] != 0)//判断j列是否存在该数
j++;
//如果该列不存在待添加的数字,进行记录操作(包括记录Routine,填充矩阵)
if(j < NUM)
cube[i][j] = n, Routine[n][i] = j,++i, j = 0;
else
{
loop:
while(i >= 1 && Routine[n][i-1] == -1)//向上找到初始不存在的该数行号
i--;
//进行回溯操作
if( i >= 1)
{
cube[i - 1][ Routine[n][i - 1] ] = 0;
j = Routine[n][i - 1] + 1;
Routine[n][i - 1] = -1;
i--;
}
else if(i <= 0)
{
return false;
}
}
}
}
return true;
}
int main()
{
Initialize();
FillNum(1);
Print();
cin.ignore();
return 0;
}
由于不断的填充,后面的数字填入的时候计算量不断减少,所以很快就能出结果了!
如下是一种解法:
9 1 5 8 3 4 6 2 7
8 2 6 1 7 5 3 4 9
1 6 2 7 4 8 5 9 3
6 4 1 3 9 2 8 7 5
2 9 8 4 5 6 7 3 1
3 7 9 2 8 1 4 5 6
5 3 4 9 6 7 2 1 8
7 5 3 6 2 9 1 8 4
4 8 7 5 1 3 9 6 2
后记:
就这么一个小程序,花了我不少时间,什么原因呢?程序写的挺快,找一个bug花了我3个多小时, 结果少了一个if判断,唉, 不过找出来的感觉还是蛮不错的哦!