代码改变世界

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;
}

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