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日

相关文章

  • 基于C#实现简易的键盘记录器

    基于C#实现简易的键盘记录器 简介 键盘记录器是一种记录键盘输入器的程序,它可以记录用户键盘操作的所有内容。本攻略将基于C#实现一款简易的键盘记录器。 构建步骤 1. 获取输入 键盘记录器需要获取用户键盘输入,我们可以使用System.Windows.Forms中的Keyboard来获取。 private void RecordKeystrokes() { …

    C# 2023年6月6日
    00
  • ASP.NET MVC实现区域或城市选择

    当我们需要实现区域或城市选择的功能时,可以使用 ASP.NET MVC 框架来实现。下面是详细的攻略: 步骤1:创建数据库 在 SQL Server 中创建一个名为“City”的数据库,并添加以下表: Province 表 列名 数据类型 Id int Name nvarchar(50) City 表 列名 数据类型 Id int Name nvarchar…

    C# 2023年5月12日
    00
  • C#高性能动态获取对象属性值的步骤

    下面是关于C#高性能动态获取对象属性值的步骤的完整攻略。 1. 利用反射获取属性信息 在C#中,我们可以使用反射来获取指定对象的属性信息,包括属性的名称、类型、值等。反射是C#编程中的一个重要概念,可以通过System.Reflection命名空间下的Type类、MethodInfo类、PropertyInfo类等相关类型来实现。 示例代码: using S…

    C# 2023年6月1日
    00
  • C#使用foreach语句简单遍历数组的方法

    C#的foreach语句是一种简单遍历数组的方法,可以快速方便地遍历数组中的元素。下面我们来详细讲解如何使用foreach语句进行数组遍历: 1.基本语法 foreach语句的基本语法如下: foreach (var item in array) { // 遍历的操作 } 其中var item是用来表示遍历到的数组元素的变量名,array则是需要遍历的数组名…

    C# 2023年6月7日
    00
  • 详解C# 泛型中的数据类型判定与转换

    接下来我将为你详细讲解“详解C#泛型中的数据类型判定与转换”的完整攻略。 1. 前言 本篇文章介绍如何在C#泛型中进行数据类型的判定和转换,这是C#编程中非常常见的需求,尤其在开发框架和类库时尤为频繁。因此,本文详细介绍了C#泛型中常用的数据类型判定和转换方式。 2. 常用的类型判定和转换方式 2.1 类型判定 2.1.1 as 运算符 as 运算符是C#语…

    C# 2023年5月14日
    00
  • 详解 iOS 系统中的视图动画

    详解 iOS 系统中的视图动画 介绍 视图动画是 iOS 开发中常用的一种动画效果,它可以让应用的用户界面更加生动有趣,提高用户的交互体验。iOS 系统提供了许多动画特效供开发者使用,本文将介绍如何在 iOS 应用中实现常用的视图动画效果。 动画基础 要实现视图动画效果,首先需要了解 iOS 中动画的基础知识。在 iOS 中,我们通常使用 Core Anim…

    C# 2023年6月7日
    00
  • C#语法新特性之元组实例详解

    C#语法新特性之元组实例详解 什么是元组? 元组是C# 7.0版本引入的一种新的类型,它可以存储一组数据,而不是单一类型的数据。它的出现使得我们可以更方便地组合和传递数据。 元组可以用于处理多个返回值,而不必引入一个专门的类型来保存它们。元组内部可以存储不同类型的数据,这是它与数组和列表等常规集合类型的主要区别。 如何使用元组? 创建元组 创建元组很简单,可…

    C# 2023年5月31日
    00
  • C#使用 NAudio 实现音频可视化的方法

    C#使用 NAudio 实现音频可视化的方法 NAudio 是一款C#语言开发的音频处理库,可以帮助我们完成各种音频处理任务,包括音频的播放、录制、混音等操作。在本文中,我们将介绍如何使用 NAudio 实现音频可视化。 第一步:引入 NAudio 库 首先,我们需要在项目中引入 NAudio 库。在Visual Studio中,可以通过NuGet添加依赖项…

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