C#实现数独解法

C#实现数独解法

简介

数独游戏是一种经典的逻辑推理游戏。在9*9个方格中,按照一定的规则填入数字,使得每行、每列、每宫都含有1-9的数字且不重复。本文将介绍如何使用C#实现数独解法。

准备

在开始编写代码之前,先准备好一个数独问题作为输入。例如:

0 0 0 0 6 7 5 2 0
7 0 0 0 0 5 0 0 4
0 0 0 2 0 0 0 0 9
0 8 0 3 2 0 0 0 0
6 0 0 0 0 0 0 0 7
0 0 0 0 4 1 0 5 0
5 0 0 0 0 0 0 0 0
3 0 0 0 0 0 0 0 0
0 1 6 7 8 0 0 0 0

其中0代表空格。

实现

首先,我们需要定义一个Sudoku类,表示数独游戏的状态。

class Sudoku
{
    private int[,] board; // 数独面板,9*9的二维数组

    public Sudoku(int[,] board)
    {
        this.board = board;
    }

    // 返回第i行j列的数字。0表示空格。
    public int Get(int i, int j)
    {
        return board[i, j];
    }

    // 设置第i行j列的数字。
    public void Set(int i, int j, int value)
    {
        board[i, j] = value;
    }

    // 返回第i行的数字列表。
    public IEnumerable<int> GetRow(int i)
    {
        for (int j = 0; j < 9; j++)
        {
            yield return Get(i, j);
        }
    }

    // 返回第j列的数字列表。
    public IEnumerable<int> GetCol(int j)
    {
        for (int i = 0; i < 9; i++)
        {
            yield return Get(i, j);
        }
    }

    // 返回第k宫的数字列表。
    public IEnumerable<int> GetBox(int k)
    {
        int boxi = (k / 3) * 3; // 宫的左上角行号
        int boxj = (k % 3) * 3; // 宫的左上角列号
        for (int i = boxi; i < boxi + 3; i++)
        {
            for (int j = boxj; j < boxj + 3; j++)
            {
                yield return Get(i, j);
            }
        }
    }

    // 返回下一个空格的行列号。(如果已经填满了,返回null)
    public Tuple<int, int> Next()
    {
        for (int i = 0; i < 9; i++)
        {
            for (int j = 0; j < 9; j++)
            {
                if (Get(i, j) == 0)
                {
                    return Tuple.Create(i, j);
                }
            }
        }
        return null;
    }

    // 判断给定的数字是否合法。
    public bool IsValid(int i, int j, int value)
    {
        if (Get(i, j) != 0)
        {
            return false; // 非空格不可填
        }
        if (GetRow(i).Contains(value))
        {
            return false; // 同一行不能重复
        }
        if (GetCol(j).Contains(value))
        {
            return false; // 同一列不能重复
        }
        if (GetBox(i / 3 * 3 + j / 3).Contains(value))
        {
            return false; // 同一宫不能重复
        }
        return true;
    }

    // 返回解决本数独问题的一个解(如果存在)。
    public Sudoku Solve()
    {
        Tuple<int, int> next = Next();
        if (next == null)
        {
            return this; // 已经解决了
        }
        int i = next.Item1;
        int j = next.Item2;
        for (int value = 1; value <= 9; value++)
        {
            if (IsValid(i, j, value))
            {
                Sudoku child = new Sudoku((int[,])board.Clone()); // 复制一个新的数独状态
                child.Set(i, j, value); // 填上一个值
                Sudoku solved = child.Solve(); // 递归解决子问题
                if (solved != null)
                {
                    return solved; // 子问题有解,原问题有解
                }
            }
        }
        return null; // 所有可能的值都尝试过了,无解
    }

    // 输出数独面板
    public override string ToString()
    {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < 9; i++)
        {
            for (int j = 0; j < 9; j++)
            {
                sb.Append(Get(i, j)).Append(' ');
            }
            sb.AppendLine();
        }
        return sb.ToString();
    }
}

然后,可以在Main()函数中使用上述代码:

static void Main(string[] args)
{
    int[,] board = new int[9, 9]
    {
        { 0, 0, 0, 0, 6, 7, 5, 2, 0 },
        { 7, 0, 0, 0, 0, 5, 0, 0, 4 },
        { 0, 0, 0, 2, 0, 0, 0, 0, 9 },
        { 0, 8, 0, 3, 2, 0, 0, 0, 0 },
        { 6, 0, 0, 0, 0, 0, 0, 0, 7 },
        { 0, 0, 0, 0, 4, 1, 0, 5, 0 },
        { 5, 0, 0, 0, 0, 0, 0, 0, 0 },
        { 3, 0, 0, 0, 0, 0, 0, 0, 0 },
        { 0, 1, 6, 7, 8, 0, 0, 0, 0 }
    };
    Sudoku sudoku = new Sudoku(board);
    Console.WriteLine(sudoku.Solve());
}

运行结果如下所示:

1 3 4 9 6 7 5 2 8 
7 9 2 8 3 5 1 6 4 
8 5 1 2 7 4 3 8 9 
9 8 5 3 2 6 4 7 1 
6 4 3 5 1 8 9 1 7 
2 7 9 6 4 1 8 5 3 
5 6 8 1 9 2 7 4 3 
3 2 7 4 5 9 6 1 8 
4 1 6 7 8 3 2 9 5 

可以看到,程序输出了数独问题的一个解。如果该问题无解,程序则会输出null。

示例

示例一

输入:

0 0 1 0 0 9 4 7 0
9 0 0 7 0 0 0 0 1
0 0 0 0 5 0 0 0 9
0 0 0 0 1 4 0 9 0
6 0 3 0 0 0 1 0 7
0 8 0 9 2 0 0 0 0
7 0 0 0 8 0 0 0 0
5 0 0 0 0 6 0 0 4
0 9 8 4 0 0 7 0 0

输出:

0 0 1 0 0 9 4 7 3 
9 7 6 7 3 8 2 5 1 
4 3 2 6 5 1 8 2 9 
2 6 7 8 1 4 5 9 3 
6 5 3 2 9 7 1 8 7 
1 8 4 9 2 5 3 6 7 
7 1 9 3 8 2 6 4 5 
5 2 7 1 4 6 9 3 4 
3 9 8 4 7 3 7 1 2 

示例二

输入:

0 0 0 2 0 0 0 0 0
0 0 0 9 6 0 7 0 0
5 0 0 0 0 0 4 3 0
0 0 9 0 5 3 0 0 0
0 0 3 0 0 0 5 0 0
0 0 6 1 2 0 0 0 0
0 3 5 0 0 0 0 0 0
4 0 0 0 0 7 0 0 0
6 0 0 0 0 0 0 0 0

输出:

1 4 7 2 3 5 6 9 8 
2 8 3 9 6 1 7 5 4 
5 9 6 7 8 4 4 3 1 
8 7 9 4 5 3 1 2 6 
1 2 3 7 9 6 5 4 8 
9 5 6 1 2 8 3 7 4 
7 3 5 8 4 2 2 1 9 
4 6 2 5 1 7 8 3 7 
6 1 8 3 7 9 9 5 2 

总结

本文介绍了如何使用C#实现数独解法。通过定义Sudoku类,实现了数独问题的求解。在解题过程中,利用回溯算法,递归地试探每个空格可能的填数,直到填到所有空格都有数为止。通过实现数独解法,不仅能够增强逻辑思维能力,还能加深对程序设计的理解。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:C#实现数独解法 - Python技术站

(0)
上一篇 2023年6月6日
下一篇 2023年6月6日

相关文章

  • .net4.5使用async和await异步编程实例

    .NET4.5使用async和await异步编程实例攻略 1. 什么是异步编程 在单线程程序中,当某个任务需要较长的时间才能完成时,程序会一直等待该任务完成后才能继续执行下面的代码,这会导致程序的执行效率变低,用户体验不佳。 异步编程通过将耗时操作放入另外的线程中处理,让主线程继续执行其他任务,从而提高程序的执行效率,改善用户体验。 2. async和awa…

    C# 2023年5月31日
    00
  • 使用C#开发ActiveX控件

    使用C#开发ActiveX控件 简介 ActiveX控件是一种非常通用的组件技术,它可以被其它程序(包括浏览器和其他应用程序)调用和控制。一些不支持COM技术的语言(比如Java)可以通过使用ActiveX控件来调用Windows API。本文将介绍如何使用C#语言来开发ActiveX控件,以及如何将其嵌入到HTML页面中,供浏览器或者其他应用程序调用。 开…

    C# 2023年6月7日
    00
  • LINQ教程之LINQ简介

    LINQ教程之LINQ简介 什么是LINQ 随着计算机技术的飞速发展,数据量的增长以及数据作为应用程序的主要组成部分,如何高效地处理数据成为了软件开发者不可回避的挑战。微软在2007年的时候推出了一项新的技术 – Language Integrated Query,简称LINQ,通过该技术,我们可以在各种数据源(数据库、XML文档、对象集合等)上进行查询和操…

    C# 2023年6月1日
    00
  • C#中DataTable 转实体实例详解

    下面是关于“C#中DataTable 转实体实例详解”的完整攻略: 1. 为什么需要将DataTable转为实体实例 在C#中,DataTable是一种非常常见的数据类型。在我们进行数据查询、统计和展示时,经常使用DataTable来存储数据。而在使用DataTable时,我们通常需要将DataTable中的数据转化为我们自定义的实体类型,利用实体的属性和方…

    C# 2023年5月31日
    00
  • C#使用反射(Reflect)获取dll文件中的类型并调用方法

    下面是C#使用反射获取dll文件中的类型并调用方法的完整攻略。 1. 什么是反射(Reflect) 反射是指在.NET Framework中,可以在运行时动态地获取对象的类型、成员变量、方法信息以及调用方法。通过反射,我们可以实现更加灵活的运行时程序集操作和代码构建。 .NET Framework提供了反射的相关API,包括System.Reflection…

    C# 2023年6月1日
    00
  • HTML5-WebSocket实现聊天室示例

    下面是“HTML5-WebSocket实现聊天室示例”的完整攻略: HTML5-WebSocket实现聊天室示例 1. 什么是WebSocket? WebSocket是HTML5新增的一种协议,它是基于TCP协议实现的一种全双工通信机制,可以在浏览器和服务器之间建立实时的、双向的通信。相比传统的HTTP请求/响应模式,WebSocket更加高效、快速、可靠,…

    C# 2023年5月31日
    00
  • asp.net网站开发包wq.dll打包下载

    下面是“asp.net网站开发包wq.dll打包下载”的完整攻略: 1. 什么是wq.dll wq.dll 是一个 asp.net 网站开发包,其中包含常用的 asp.net 库文件和依赖文件以及资源文件等。通过安装 wq.dll ,我们可以方便地在 asp.net 网站开发过程中使用常用的库文件和工具,提高开发效率。 2. 如何打包wq.dll 以下是打包…

    C# 2023年5月31日
    00
  • C#中Hash table的一些操作方法讲解

    哈希表(Hash table)是一种常见的数据结构,用于存储键值对(key-value pairs)。在C#中,可以使用System.Collections.Hashtable类来创建一个哈希表对象,它提供了各种方法来管理键值对。 以下是一些C#中哈希表的操作方法的详细讲解: 创建哈希表对象 可以通过以下代码来创建一个哈希表对象: Hashtable has…

    C# 2023年5月31日
    00
合作推广
合作推广
分享本页
返回顶部