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

 

代码
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>() { 123456789 };
                
return candidate;
            }
            
set { candidate = value; }
        }
        
private Dictionary<intint> duplicateDel; //重复删除候选数次数的记录,以便恢复       
        public Dictionary<intint> DuplicateDel
        {
            
get
            {
                
if (duplicateDel == null)
                    duplicateDel 
= new Dictionary<intint>();
                
return duplicateDel;
            }
            
set { duplicateDel = value; }
        }
        
private int value = 0;
        
//单元格的值
        public int Value { getreturn 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] { 000333666 };//处理九宫格的约束
        int series;
        Random random 
= new Random();
        
/// <summary>
        
/// 开始生成数独
        
/// </summary>
        public void StartFillTable()
        {
            Cell[,] table 
= new Cell[99];
            
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(
"----------------------------------------------");

        }
    }
}

 

 

posted @ 2010-01-25 22:35  山天大畜  阅读(1301)  评论(8编辑  收藏  举报