数独算法及源代码

转载自数独算法及源代码

朋友手机装有数独游戏,开会报告等无聊的场合常拿来玩玩,游戏的算法似乎并不难,想想我也能做出来。今早闲的蛋疼,就写了个数独玩玩。记录如下:

数独规则不知道的可以参考这里游戏关键的算法就在于生成一个符合数独游戏规则的初始矩阵,首先想到的自然是号称万能解题法的“搜索+剪枝”了。

1.       产生符合数独规则的初始矩阵

第一行是随机生成的1~9的排列,第29行就要通过搜索来产生了。对于第29行的每一个空格,要从19逐个尝试放入,看同一列、同一行、同一个3×3的小方阵中是否出现过相同的数字,若没有就尝试放入,然后递归地搜索下一个位置的数字,若19都不行就返回上一个位置尝试下一个数字。直到找到一组解就返回。

先上C++代码:

#include<iostream>
#include<algorithm>
#include <ctime>
using namespace std;
 
int Initial_State [ 10 ] [ 10 ] ; 
 
bool get_Initial_State( int i , int j  )  //搜索第( i , j )位置处可以存储的数字,找到解则返回true,否则返回false
{
    if( i > 9 || j > 9 ) 
        return true;
 
    for( int k = 1 ; k <= 9 ; ++k ) 
    {
        bool can = true;                // can 变量用于记录数字k能否放在 ( i , j ) 处
        for( int m = 1 ; m < i ; ++m ) 
            if( Initial_State[m][j] == k )  // 检查同一列是否出现过数字k
            {
                can = false ;
                break ;
            }
        if ( can ) 
            for( int n = 1 ; n < j ; ++n ) 
                if( Initial_State[i][n] == k )  // 检查同一行是否出现过数字k
                {
                    can = false ;
                    break; 
                }
        if( can ) 
        {
            int up1 = ( i/3 ) * 3 + 3 ; // (i,j)方格所在的3×3小方格i坐标的上限
            int up2 = ( j/3 ) *3 + 3;  // (i,j)方格所在的3×3小方格在j坐标的上限
 
            if( i % 3 == 0 )    //这是针对特殊情况的处理
                up1 = i ; 
            if( j % 3 == 0 ) 
                up2 = j ;
 
            for( int p = up1-2 ; p <= up1 ; ++p  )  /* 检查在3×3的小方格中是否出现了同一个数字 */
            {
                if( can == false )  /* 跳出外层循环 */
                    break ;
                for( int q = up2-2 ; q <= up2 ; ++q ) 
                    if( Initial_State[p][q] == k ) 
                    {
                        can = false ;
                        break ;
                    }
            }
        }
        if( can ) 
        {
            Initial_State[i][j] = k ; 
            if( j<9 ) 
            {
                if( get_Initial_State( i  , j +1 ) )  /* 到同一行的下一位置开始搜索 */
                    return true ;  
            }
            else
            {
                if( i < 9 )  
                {
                    if( get_Initial_State( i + 1 , 1 ) )    /* 到下一行的第一个空格开始搜索 */
                        return true ;
                }
                else
                    return true ;  /* i >= 9  && j >= 9  , 搜索结束 */
 
            }
            Initial_State[i][j] = 0 ;  /* 关键这一步:找不到解就要回复原状,否则会对下面的搜索造成影响 */
        }
    }
    return false ;  /*  1到9都尝试过都不行,则返回递归的上一步 */
}
 
void start() 
{
    srand ( unsigned ( time (NULL) ) );  /* 产生random_shuffle的随机数种子 */
    for( int i = 1  ; i <= 9 ; ++i )
        for( int j = 1 ; j <= 9 ; ++j )
            Initial_State[i][j] = 0 ;
 
    for( int i = 1 ; i <= 9 ; ++i ) 
        Initial_State[1][i] = i ; 
 
    random_shuffle( &( Initial_State[1][1]) , &( Initial_State[1][10])  ) ;  /* 第一行随机排列产生 */
 
    get_Initial_State( 2 , 1 ) ;  /* 从第二行开始搜索 */
}
 
int main()
{
    start( ) ;
    for( int i = 1 ; i <= 9 ; ++ i ) 
    {
        for( int j = 1 ; j <= 9 ; ++j ) 
            cout<< Initial_State [i][j] <<" " ;
        cout<<endl; 
    }
    getchar() ; 
    return 0 ;
}

上面的算法在找到第一个解后就返回了,这样当第一行数字确定后,则只能得到一个矩阵了。也就是说上面的程序只能产生 9! 个数独初试矩阵。

2.        获胜条件

还有一点要注意的是检查用户的解正确与否的标准不是比较用户输入得到的矩阵与我们开始产生的初试矩阵是否相同,而是判断用户的矩阵是否满足数独的游戏规则。

这是因为一个初始矩阵被挖掉一些空格后,可能会有不止一种正确解,这里我就不详细说,这样的例子很容易举出。

3. 程序源代码下载 

用 C++ 写完上面的代码,发现 MFC 半年没用,不会做界面了。。。于是用 javascript 写了出来。程序全部在一个 html 文件中。


  • 9
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
可以为您提供 CSharp 实现数独算法源代码,以下是示例代码: using System; namespace SudokuSolver { class Program { static void Main(string[] args) { int[,] board = new int[,] { {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0} }; if (SolveSudoku(board)) { Console.WriteLine("Sudoku solved:"); PrintBoard(board); } else { Console.WriteLine("Unable to solve Sudoku."); } } static bool SolveSudoku(int[,] board) { int row = 0; int col = 0; bool isEmpty = true; for (int i = 0; i < 9; i++) { for (int j = 0; j < 9; j++) { if (board[i, j] == 0) { row = i; col = j; isEmpty = false; break; } } if (!isEmpty) { break; } } if (isEmpty) { return true; } for (int num = 1; num <= 9; num++) { if (IsValid(board, row, col, num)) { board[row, col] = num; if (SolveSudoku(board)) { return true; } else { board[row, col] = 0; } } } return false; } static bool IsValid(int[,] board, int row, int col, int num) { for (int i = 0; i < 9; i++) { if (board[row, i] == num) { return false; } if (board[i, col] == num) { return false; } int boxRow = 3 * (row / 3) + i / 3; int boxCol = 3 * (col / 3) + i % 3; if (board[boxRow, boxCol] == num) { return false; } } return true; } static void PrintBoard(int[,] board) { for (int i = 0; i < 9; i++) { for (int j = 0; j < 9; j++) { Console.Write(board[i, j] + " "); } Console.WriteLine(); } } } }
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值