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
初始矩阵如上.
好了, 附上我的以行为单位的回溯解法

这个和crj学长的解稍有不同,是两层回溯,可以求出全部的解,呵呵。

//  Solver For Number Puzzle From Microsoft Club
//  71105129 CloudiDust

#include 
< fstream >
#include 
< algorithm >

using   namespace  std;

struct  FreqList
{
    
int num;
    
int count;
    
bool operator<(const FreqList& another) const
    
{
        
return (count > another.count);
    }

}
;

const   int  boardSize  =   9 ;
int  gameBoard[boardSize][boardSize]  =   {{0,0}} ;
int  columnInRow[boardSize  +   1 ][boardSize];
bool  isInColumn[boardSize  +   1 ][boardSize];
bool  isFixed[boardSize  +   1 ][boardSize];
FreqList processList[boardSize];

void  occupy( const   int  row,  const   int  col,  const   int  num)
{
    gameBoard[row][col] 
= num;
    columnInRow[num][row] 
= col;
    isInColumn[num][col] 
= true;
}


void  free( const   int  row,  const   int  col)
{
    
int &num = gameBoard[row][col];
    columnInRow[num][row] 
= -1
    isInColumn[num][col] 
= false;
    num 
= 0;
}
    

void  initialize()
{    
    
// 初始化数字位置标记矩阵
    for (int num = 0; num <= boardSize; ++num)
    
{
        
for (int index = 0; index < boardSize; ++index)
        
{
            columnInRow[num][index] 
= -1;
            isInColumn[num][index] 
= false;
            isFixed[num][index] 
= false;
        }

    }

    
    
// 初始化处理顺序表
    for (int num = 1; num <= boardSize; ++num)
    
{
        processList[num 
- 1].num = num;
        processList[num 
- 1].count = 0;
    }

    
    
// 读入初始数据
    ifstream dataFile("mcnp.in");
    
for (int rowIndex = 0; rowIndex < boardSize; ++rowIndex)
    
{
        
for (int columnIndex = 0; columnIndex < boardSize; ++columnIndex)
        
{
            
int temp;
            dataFile 
>> temp;
            
if (temp)
            
{
                occupy(rowIndex, columnIndex, temp);
                isFixed[temp][rowIndex] 
= true;
                
++processList[temp - 1].count;
            }

        }

    }

    
    dataFile.close();
    
    
// 对处理顺序表进行排序
    
// 在初始数据中出现次数越多的数字,将越优先处理
    sort(processList, processList + boardSize);
}


void  print(ostream &  resFile);
bool  place( const   int const   bool );

void  process()
{
    ofstream resFile(
"mcnp.out");
    
bool isPlaced[boardSize] = {false};
    
int stackTop = 0;
    
    
while (stackTop > -1)
    
{
        
if (stackTop == boardSize)
        
{
            print(resFile);
            
--stackTop;
        }

        
else 
        
{
            isPlaced[stackTop] 
= place(processList[stackTop].num,isPlaced[stackTop]);
            
if (isPlaced[stackTop])
                
++stackTop;
            
else
                
--stackTop;
        }

    }

    resFile.close();
}


bool  place( const   int  num,  const   bool  hasBeenPlacedBefore)
{
    
int currentRow;
    
    
if (!hasBeenPlacedBefore)
    
{
        currentRow 
= 0;
        
while ((currentRow < boardSize) && isFixed[num][currentRow]) ++currentRow;
    }

    
else
    
{
        currentRow 
= boardSize - 1;
        
while ((currentRow >= 0&& isFixed[num][currentRow]) --currentRow;
    }

    
    
while (currentRow > -1)
    
{
        
if (currentRow == boardSize) return true;
        
else
        
{
            
int& prevColumn = columnInRow[num][currentRow];
            
int currentColumn = prevColumn + 1;
            
            
while (currentColumn < boardSize 
                    
&& (isInColumn[num][currentColumn]
                        
|| gameBoard[currentRow][currentColumn] != 0))
                
++currentColumn;
            
            
// 找不到下一个合适的列吗?
            if (currentColumn == boardSize)
            
{
                
//找不到,释放本行数据,回溯到上一可以修改的行
                if (prevColumn > -1)
                    free(currentRow, prevColumn);
                
--currentRow;
                
while ((currentRow >= 0&& isFixed[num][currentRow]) --currentRow;
            }

            
else
            
{
                
//找到了,填充新位置,选择下一可以修改的行
                if (prevColumn > -1)
                    free(currentRow, prevColumn);
                occupy(currentRow, currentColumn, num);
                
++currentRow;
                
while ((currentRow < boardSize) && isFixed[num][currentRow]) ++currentRow;
            }

        }

    }

    
    
return false;
}


void  print(ostream &  resFile)
{
    
for (int rowIndex = 0; rowIndex < boardSize; ++rowIndex)
    
{
        
for (int columnIndex = 0; columnIndex < boardSize; ++columnIndex)
        
{
            resFile 
<< gameBoard[rowIndex][columnIndex] << " ";
        }

        resFile 
<< endl;
    }

    resFile 
<< endl;
}

        
int  main()
{
    initialize();
    process();
    
return 0;
}

 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值