数独的优化回朔算法(源代码)

 

ExpandedBlockStart.gif 代码
using  System;
using  System.Collections.Generic;
using  System.Linq;
using  System.Text;

namespace  Test
{
    
class  Program
    {
        
static   void  Main( string [] args)
        {
            CellMethod method 
=   new  CellMethod();
            method.StartFillTable();
        }
    }

    
///   <summary>
    
///  单元格
    
///   </summary>
     class  Cell
    {
        
private  List < int >  candidate;  // 候选数
         public  List < int >  Candidate
        {
            
get
            {
                
if  (candidate  ==   null )
                    candidate 
=   new  List < int > () {  1 2 3 4 5 6 7 8 9  };
                
return  candidate;
            }
            
set  { candidate  =  value; }
        }
        
private  Dictionary < int int >  duplicateDel;  // 重复删除候选数次数的记录,以便恢复       
         public  Dictionary < int int >  DuplicateDel
        {
            
get
            {
                
if  (duplicateDel  ==   null )
                    duplicateDel 
=   new  Dictionary < int int > ();
                
return  duplicateDel;
            }
            
set  { duplicateDel  =  value; }
        }
        
private   int  value  =   0 ;
        
// 单元格的值
         public   int  Value {  get return   this .value; } set  {  this .value  =  value; } }
    }

    
///   <summary>
    
///  数独方法
    
///   </summary>
     class  CellMethod
    {
        
private   delegate   bool  RelativeCellMethod(Cell[,] table,  int  i,  int  j,  int  index);

        
private   int [] nineCells  =   new   int [ 9 ] {  0 0 0 3 3 3 6 6 6  }; // 处理九宫格的约束
         int  series;
        Random random 
=   new  Random();
        
///   <summary>
        
///  开始生成数独
        
///   </summary>
         public   void  StartFillTable()
        {
            Cell[,] table 
=   new  Cell[ 9 9 ];
            
while  ( true )
            {
                
for  ( int  i  =   0 ; i  <   9 ; i ++ )
                    
for  ( int  j  =   0 ; j  <   9 ; j ++ // 初始化数独表
                        table[i, j]  =   new  Cell();

                
bool  flag  =  FillCell(table,  0 ); // 填充数独表
                 if  (flag) // 如果生成数独成功,则显示这个数独
                    Show(table);
                Console.ReadKey();
            }
        }

        
///   <summary>
        
///  为单元格设定值
        
///   </summary>
        
///   <param name="cell"> 单元格 </param>
        
///   <returns> 返回结果 </returns>
         public   bool  SetValue(Cell cell)
        {
            
if  (cell.Value  !=   0 )
            {
                
throw   new  InvalidOperationException( " 异常!不能重复对一个单元格进行赋值! " );
            }
            
if  (cell.Candidate.Count  ==   0 )
            {
                
return   false ;
            }
            
// 随机选取单元格中的一个候选数为值,并移除该候选数
            series  =  random.Next( 0 , cell.Candidate.Count  -   1 );
            cell.Value 
=  cell.Candidate[series];
            cell.Candidate.RemoveAt(series);
            
return   true ;
        }

        
///   <summary>
        
///  处理相关单元格
        
///   </summary>
        
///   <param name="cellMethod"> 调用方法 </param>
        
///   <param name="table"> </param>
        
///   <param name="index"> 索引 </param>
        
///   <returns> 返回结果 </returns>
         private   bool  DealRelativeCell(RelativeCellMethod cellMethod, Cell[,] table,  int  index)
        {
            
bool  isSetUniqueCellMethod  =   false ;
            
if  (cellMethod  ==  SetUniqueCellCandidate)
                isSetUniqueCellMethod 
=   true ;
            
bool  flag  =   true ;
            Cell cell 
=  table[index  /   9 , index  %   9 ];
            
for  ( int  i  =   0 ; i  <   9 ; i ++ )
            {
                
// 同列单元格
                 if  (i  !=  index  /   9 )
                {
// 不能等于本单元格
                    
// 如果任意一个赋值失败则直接跳出循环,以下同理
                     if  (isSetUniqueCellMethod  &&   ! flag)  break ;
                    flag 
&=  cellMethod(table, i, index  %   9 , index);
                }
                
// 同行单元格
                 if  (i  !=  index  %   9 )
                {
// 不能等于本单元格
                     if  (isSetUniqueCellMethod  &&   ! flag)  break ;
                    flag 
&=  cellMethod(table, index  /   9 , i, index);
                }
            }
            
// 同九宫格单元格的剩余四个单元格
             for  ( int  i  =  nineCells[index  /   9 ]; i  <  nineCells[index  /   9 +   3 ; i ++ )
            {
                
for  ( int  j  =  nineCells[index  %   9 ]; j  <  nineCells[index  %   9 +   3 ; j ++ )
                {
                    
if  (i  !=  index  /   9   &&  j  !=  index  %   9 )
                    {
                        
if  (isSetUniqueCellMethod  &&   ! flag)  break ;
                        flag 
&=  cellMethod(table, i, j, index);
                    }
                }
            }
            
if  (cellMethod  ==  RemoveCellCandidate  &&  flag)
            {
// 如果都移除候选数成功,则判断有没有只剩一个候选数的为赋值的单元格,有则赋值上
                RelativeCellMethod setCandidateMethod  =   new  RelativeCellMethod(SetUniqueCellCandidate);
                flag 
&=  DealRelativeCell(setCandidateMethod, table, index);
            }
            
if  (cellMethod  ==  RecoverCellCandidate)
            {
                cell.Value 
=   0 ;
            }
            
return  flag;
        }

        
///   <summary>
        
///  填充单元格
        
///   </summary>
        
///   <param name="table"> </param>
        
///   <param name="index"> 索引 </param>
        
///   <returns> 返回结果 </returns>
         private   bool  FillCell(Cell[,] table,  int  index)
        {
            RelativeCellMethod removeCandidateMethod 
=   new  RelativeCellMethod(RemoveCellCandidate);
            RelativeCellMethod recoverCandidateMethod 
=   new  RelativeCellMethod(RecoverCellCandidate);

            
if  (index  >=   81 )
            {
// 如果索引超出范围,则表示数独已成功生成,直接返回
                 return   true ;
            }
            
if  (table[index  /   9 , index  %   9 ].Value  !=   0 )
            {
// 如果索引的单元格已赋值,则直接跳到下一个索引赋值
                 return  FillCell(table, index  +   1 );
            }
            
bool  flag  =   true ;
            List
< int >  nextCandidates  =   new  List < int > ();
            
// 预先保存好改单元格的候选数序列,如果所有候选数都不成功,则把候选数全部还原之后再返回
            nextCandidates.AddRange(table[index  /   9 , index  %   9 ].Candidate);

            
while  (table[index  /   9 , index  %   9 ].Candidate.Count  >   0   &&  flag)
            {
// 如果单元格候选数个数大于0,且标记为真,则循环试探候选数
                SetValue(table[index  /   9 , index  %   9 ]); // 为单元格赋值
                flag  &=  DealRelativeCell(removeCandidateMethod, table, index); // 移除相关单元格的对应这个值的候选数
                 if  ( ! flag)
                {
// 如果移除候选数失败,则恢复候选数,并继续下个循环
                    DealRelativeCell(recoverCandidateMethod, table, index);
                }
                
else
                {
// 如果移除候选数成功,则继续试探填充下一个单元格
                    flag  &=  FillCell(table, index  +   1 );
                    
if  ( ! flag)
                    {
// 如果填充下一个单元格失败,则恢复候选数,并继续下个循环
                        DealRelativeCell(recoverCandidateMethod, table, index);
                    }
                    
else
                    {
// 如果填充下一个单元格成功,则直接返回(运行到这里肯定表示整个数独已成功生成!)
                         return   true ;
                    }
                }
                flag 
=   ! flag; // 把标志取反,继续下个循环
            }
            
if  (table[index  /   9 , index  %   9 ].Candidate.Count  ==   0 )
            {
// 如果所有候选数都是过了且全部失败,恢复此单元格的候选数,并返回false
                table[index  /   9 , index  %   9 ].Candidate.AddRange(nextCandidates);
                
return   false ;
            }
            
return  flag;
        }

        
///   <summary>
        
///  移除单元格的候选数
        
///   </summary>
        
///   <param name="table"> </param>
        
///   <param name="i"> </param>
        
///   <param name="j"> </param>
        
///   <param name="index"> 索引 </param>
        
///   <returns> 返回结果 </returns>
         static   private   bool  RemoveCellCandidate(Cell[,] table,  int  i,  int  j,  int  index)
        {
            
int  value  =  table[index  /   9 , index  %   9 ].Value;
            
bool  flag  =   true ;
            
if  (table[i, j].Candidate.Contains(value))
            {
// 如果单元格候选数有此数,移除之
                table[i, j].Candidate.Remove(value);
                
if  (table[i, j].Candidate.Count  ==   0   &&  table[i, j].Value  ==   0 )
                {
// 如果单元格移除此候选数之后,并未赋值且候选数量为0,则失败,回滚
                    flag  =   false ;
                }
            }
            
else   if  (table[i, j].DuplicateDel.ContainsKey(value))
            {
// 如果单元格候选数没有此数,且在重复删除的字典里有此数,则重复删除字典此数对应的键值的值+1
                table[i, j].DuplicateDel[value] ++ ;
            }
            
else
            {
// 如果单元格候选数没有此数,且在重复删除的字典里没有此数,则重复删除字典添加此数的键值,并赋值为1
                table[i, j].DuplicateDel.Add(value,  1 );
            }
            
return  flag;
        }

        
///   <summary>
        
///  恢复单元格的候选数
        
///   </summary>
        
///   <param name="table"> </param>
        
///   <param name="i"> </param>
        
///   <param name="j"> </param>
        
///   <param name="index"> 索引 </param>
        
///   <returns> 返回结果 </returns>
         private   bool  RecoverCellCandidate(Cell[,] table,  int  i,  int  j,  int  index)
        {
            
int  value  =  table[index  /   9 , index  %   9 ].Value;
            
bool  flag  =   true ;

            
if  (table[i, j].DuplicateDel.ContainsKey(value))
            {
// 如果在重复删除的字典里有此数,则重复删除字典此数对应的键值的值-1
                 if  ( -- table[i, j].DuplicateDel[value]  ==   0 )
                {
                    table[i, j].DuplicateDel.Remove(value);
                }
            }
            
else   if  ( ! table[i, j].Candidate.Contains(value))
            {
// 如果单元格候选数没有此数,添加之
                table[i, j].Candidate.Add(value);
            }

            
return  flag;
        }

        
///   <summary>
        
///  为候选数个数为一的单元格赋值
        
///   </summary>
        
///   <param name="table"> </param>
        
///   <param name="i"> </param>
        
///   <param name="j"> </param>
        
///   <param name="index"> 索引 </param>
        
///   <returns> 返回结果 </returns>
         private   bool  SetUniqueCellCandidate(Cell[,] table,  int  i,  int  j,  int  index)
        {
            RelativeCellMethod removeCandidateMethod 
=   new  RelativeCellMethod(RemoveCellCandidate);
            RelativeCellMethod recoverCandidateMethod 
=   new  RelativeCellMethod(RecoverCellCandidate);

            
bool  flag  =   true ;
            
if  (table[i, j].Value  ==   0   &&  table[i, j].Candidate.Count  ==   1 )
            {
// 如果单元格移除此候选数之后,候选数量为1,则直接为此单元格赋值剩下的候选数
                 int  oldValue  =  table[i, j].Candidate[ 0 ]; // 保存该唯一候选数,以便如果失败恢复
                flag  &=  SetValue(table[i, j]);
                flag 
&=  DealRelativeCell(removeCandidateMethod, table, i  *   9   +  j);
                
if  ( ! flag)
                {
// 如果移除候选数失败,则恢复候选数,回滚
                    DealRelativeCell(recoverCandidateMethod, table, i  *   9   +  j);
                    table[i, j].Candidate.Add(oldValue);
                    flag 
&=   false ;
                }
            }
            
return  flag;
        }

        
///   <summary>
        
///  显示数独
        
///   </summary>
        
///   <param name="table"> </param>
         private   void  Show(Cell[,] table)
        {
            
for  ( int  i  =   0 ; i  <   9 ; i ++ )
            {
                
for  ( int  j  =   0 ; j  <   9 ; j ++ )
                {
                    Console.Write(
" {0,2} " , table[i, j].Value);

                }
                Console.WriteLine();
            }
            Console.WriteLine(
" ---------------------------------------------- " );

        }
    }
}

 

 

转载于:https://www.cnblogs.com/cdts_change/archive/2010/01/25/1656267.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
可以为您提供 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(); } } } }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值