mstc面试题-数独

前几天学校的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
初始矩阵如上.
好了, 附上我的以行为单位的回溯解法(注意:解不止一组,这里给出一组解就可以了)

ExpandedBlockStart.gif ContractedBlock.gif /**/ /*
InBlock.gif算法思想: 这个算法题目是一个简化的数独问题。我采用的是比较经典的回溯方法,类似九皇后(排除
InBlock.gif斜线的规则)。以行为单位向矩阵中逐个的插入n(n从1到NUM),当然前提是该位置不存在数,且若放置该数
InBlock.gif不会造成冲突,这里冲突的定义是行列存在相同的值。如果存在冲突,则相应的找到正在插入的行上面的具有
InBlock.gif非初始值n的行,并进行回溯操作。
InBlock.gif
InBlock.gifAuthor: 农夫三拳(drizzlecrj@gmail.com)
ExpandedBlockEnd.gif
*/

None.gif
None.gif#include 
< iostream >
None.gif#include 
< fstream >
None.gif
None.gif
using   namespace  std;
None.gif
None.gif
const   int  NUM  =   9 ;             // 矩阵的行数
None.gif
int  cube[NUM][NUM];             // 矩阵的初始排布
None.gif
int  Routine[NUM  +   1 ][NUM];     // 对应每一个数字n在每行上的下标数组
None.gif
None.gif
// 判断该行是否已经存在数字num,r代表行号
None.gif
bool  IsExistInRow( int  r, int  num)
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif    
for(int j = 0; j < NUM; j++)
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        
if(cube[r][j] == num)
InBlock.gif            
return true;
ExpandedSubBlockEnd.gif    }

InBlock.gif    
return false;
ExpandedBlockEnd.gif}

None.gif
None.gif
// 判断该列是否存在数字num,c代表列号
None.gif
bool  IsExistInColumn( int  c, int  num)
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif    
for(int i = 0; i < NUM; i++)
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        
if(cube[i][c] == num)
InBlock.gif            
return true;
ExpandedSubBlockEnd.gif    }

InBlock.gif    
return false;
ExpandedBlockEnd.gif}

None.gif
None.gif
// 从文件初始读入矩阵并初始化Routine数组
None.gif
void  Initialize()
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif    ifstream fin(
"input.txt");
InBlock.gif    
int i, j;
InBlock.gif    
for(i = 0; i < NUM; i++)
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        
for(j = 0; j < NUM; j++)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            fin 
>> cube[i][j];
ExpandedSubBlockEnd.gif        }

ExpandedSubBlockEnd.gif    }

InBlock.gif    
for(i = 1; i <= NUM; i++)
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        
for(j = 0; j < NUM; j++)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            Routine[i][j] 
= -1;
ExpandedSubBlockEnd.gif        }

ExpandedSubBlockEnd.gif    }

ExpandedBlockEnd.gif}

None.gif
None.gif
// 打印矩阵
None.gif
void  Print()
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif    
int i, j;
InBlock.gif    
for(i = 0; i < NUM; i++)
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        
for(j = 0; j < NUM - 1; j++)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            cout 
<< cube[i][j] << ' ';
ExpandedSubBlockEnd.gif        }

InBlock.gif        cout 
<< cube[i][j] << endl;
ExpandedSubBlockEnd.gif    }

ExpandedBlockEnd.gif}

None.gif
None.gif
// 核心函数,向矩阵中插入数字n
None.gif
bool  FillNum( int  n)
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif    
if( n > NUM)
InBlock.gif        
return true;
InBlock.gif    
int i, j;
InBlock.gif    i 
= j = 0;
InBlock.gif    
while(true)
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        
if(i == NUM)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
if(FillNum(n + 1)) //填取下一个数字
InBlock.gif
                break;
InBlock.gif            
else  
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif{
InBlock.gif                
goto loop;
ExpandedSubBlockEnd.gif            }

ExpandedSubBlockEnd.gif        }

InBlock.gif        
while(i < NUM && IsExistInRow(i, n))//判断i行是否存在该数
InBlock.gif
            i++;
InBlock.gif        
//如果该行不存在待添加的数字,才进行下面的列检查
InBlock.gif
        if(i < NUM)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
while((j < NUM &&  IsExistInColumn(j, n)) || cube[i][j] != 0)//判断j列是否存在该数
InBlock.gif
                    j++;
InBlock.gif            
//如果该列不存在待添加的数字,进行记录操作(包括记录Routine,填充矩阵)
InBlock.gif
            if(j < NUM)
InBlock.gif                cube[i][j] 
= n, Routine[n][i] = j,++i, j = 0;
InBlock.gif             
else
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif{
InBlock.gifloop:
InBlock.gif                
while(i >= 1 && Routine[n][i-1== -1)//向上找到初始不存在的该数行号
InBlock.gif
                    i--;
InBlock.gif                
//进行回溯操作
InBlock.gif
                if( i >= 1)
ExpandedSubBlockStart.gifContractedSubBlock.gif                
dot.gif{
InBlock.gif                    cube[i 
- 1][ Routine[n][i - 1] ] = 0;
InBlock.gif                    j 
= Routine[n][i - 1+ 1;
InBlock.gif                    Routine[n][i 
- 1= -1;
InBlock.gif                    i
--;
ExpandedSubBlockEnd.gif                }

InBlock.gif                
else if(i <= 0)
ExpandedSubBlockStart.gifContractedSubBlock.gif                
dot.gif{
InBlock.gif                    
return false;
ExpandedSubBlockEnd.gif                 }

ExpandedSubBlockEnd.gif            }

ExpandedSubBlockEnd.gif        }

ExpandedSubBlockEnd.gif    }

InBlock.gif    
return true;
ExpandedBlockEnd.gif}

None.gif
None.gif
int  main()
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif    Initialize();
InBlock.gif    FillNum(
1);
InBlock.gif    Print();
InBlock.gif    cin.ignore();
InBlock.gif
InBlock.gif    
return 0;
ExpandedBlockEnd.gif}

由于不断的填充,后面的数字填入的时候计算量不断减少,所以很快就能出结果了!
如下是一种解法:
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判断,唉, 不过找出来的感觉还是蛮不错的哦!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值