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


    代码
    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(
    "----------------------------------------------");

            }
        }
    }
  • 相关阅读:
    oracle数据库创建表
    CMD下常用文件操作指令
    C#中int、long、float、double、decimal最大值最小值
    EF框架一对多 多对多关系总结
    如何用vue做网站,如何学习vue?--写两个经典的项目,算是入手
    swiper的使用方法,以及各种JS插件的使用通用技巧
    HTML快速布局技巧!编程的流程控制语句有三种,HTML又如何编写布局呢?
    CSS的移动端适配原理(一)-----屏幕是如何工作的(发光点原理),PC和手机的屏幕是如何渲染图片和文字
    JS语法糖总结----JS语法糖大全----一直更新
    PHPcms 客户定制的连表查询和结果排序的记录----2018-1-29 14:06
  • 原文地址:https://www.cnblogs.com/cdts_change/p/1656267.html
Copyright © 2020-2023  润新知