写个程序玩数独

2024-06-23 20:08
文章标签 程序 玩数 写个

本文主要是介绍写个程序玩数独,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

由于不可抗力的因素,导致今年(2020)的假期格外的长,毕竟还只能蜗居度过。在家里消磨时光有很多方法,比如说看剧,看书,玩游戏等。

说到玩游戏,我就想到了我初中时候看杂志时,里面会有一类题目,叫做数独。

2013053-b3c1c45feabeaf61.png
数独游戏

数独游戏的目标是用数字填充9x9的宫格,让每一列,每一行和每个3x3小九宫部分都包含1到9之间的数字。在游戏开始时,9x9的宫格中会有一些方格已填上数字。你要做的是运用逻辑来填上缺失的数字并完成宫格。不要忘记,如果出现以下情况,表示填法不正确

  • 任意一行中,有多个相同的1到9中的数字
  • 任意一列中,有多个相同的1到9中的数字
  • 任意一个3x3小宫格中,有多个相同的1到9中的数

那个时候,拿着铅笔和橡皮擦玩,一个谜题能把一个晚自修给干掉。

最近在家学习算法,学到了回溯算法这一部分,里面就提到了回溯算法的使用范围为,在一组可能的解中,搜索满足期望的解。课程介绍了回溯算法处理八皇后问题,把数独问题留作了练习题。我就用C语言写了相应的代码。

代码的核心是写一个递归函数,用于分步求解当前值是否满足要求,如果满足需求就进入下一阶段,如果下一个阶段在前一阶段基础上无解,就会回到上一阶段,换另一个值进行尝试。

按照这个思想我写了第一版代码

 void
calcSudoku( int (*arr)[9], int (*arr2)[9], int pos, int value ){if ( pos == 81){printSudoku(arr);return ;}int row = pos / 9;int col = pos % 9;int val;for ( val = 1; val < 10; val++){// 如果为0, 说明此处可以进行修改if ( arr2[row][col] == 0 ){if ( isValidStep(arr, row, col, val ) ){arr[row][col] = val;calcSudoku( arr, arr2, pos + 1, val );}} else{// 当前记录如果不为0, 说明此处是已填写区域// 跳过这个地方calcSudoku( arr, arr2, pos + 1, val );}}
}   for ( val = 1; val < 10; val++){// 如果为0, 说明此处可以进行修改if ( arr2[row][col] == 0 ){if ( isValidStep(arr, row, col, val ) ){arr[row][col] = val;calcSudoku( arr, arr2, pos + 1, val );printSudoku(arr);}} else{// 当前记录如果不为0, 说明此处是已填写区域// 跳过这个地方calcSudoku( arr, arr2, pos + 1, val );}}

结果代码会陷入一个死循环。我在代码中各种加printf来想办法找到可能的问题,然后还和之前的八皇后问题进行了比较,最终和别人的java代码做了比较之后,才发现代码的问题

  1. 原本是提供arr2作为原来数组的拷贝,用于记录哪里为0,想避免修改原来为不为0的地方, 但对于正确的回溯代码,递归记录了路径,因此在回溯的过程中,可以重设原来的状态。
  2. 判断当前值是否为0,应该是在for循环之外,可以避免不必要的计算
  3. 缺少重设原来状态的代码,导致回退之后,还是之前的状态。

经过我的修改,下面的代码才是真正能用的

void
calcSudoku( int (*metrics)[9],  int pos, int value ){if ( pos == 81 ){printSudoku(metrics);return ;}int row = pos / 9;int col = pos % 9;int val;// 如果为0, 说明此处可以进行修改if ( metrics[row][col] == 0 ){for ( val = 1; val < 10; val++){if ( isValidStep(metrics, row, col, val ) ){ // 如果能够设置当前值metrics[row][col] = val;calcSudoku( metrics, pos + 1, val ); // 前进到下一步}//从下一状态回退到当前值时,则重设当前值metrics[row][col] = 0; }} else{// 当前记录如果不为0, 说明此处是已填写区域// 跳过这个地方calcSudoku( metrics, pos + 1, val );}
}

最终版代码在GitHub上, https://github.com/xuzhougeng/learn-algo/blob/master/sudoku.c

使用方法,把之前的问题输入到一个文本中,以空格作为分隔符

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

然后运行代码,就会得到答案。

$ ./sudoku q.txt
0 0 9 4 2 0 0 6 0
0 7 0 9 0 5 3 0 2
5 0 0 0 0 3 0 9 0
0 0 0 8 0 1 0 2 0
2 6 0 0 0 0 0 5 1
0 1 8 2 0 0 4 0 0
3 8 0 0 0 4 0 1 9
0 9 4 0 3 0 6 8 5
0 2 1 0 0 8 0 3 01 3 9 4 2 7 5 6 8
8 7 6 9 1 5 3 4 2
5 4 2 6 8 3 1 9 7
4 5 3 8 7 1 9 2 6
2 6 7 3 4 9 8 5 1
9 1 8 2 5 6 4 7 3
3 8 5 7 6 4 2 1 9
7 9 4 1 3 2 6 8 5
6 2 1 5 9 8 7 3 4

这篇关于写个程序玩数独的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1088147

相关文章

uniapp接入微信小程序原生代码配置方案(优化版)

uniapp项目需要把微信小程序原生语法的功能代码嵌套过来,无需把原生代码转换为uniapp,可以配置拷贝的方式集成过来 1、拷贝代码包到src目录 2、vue.config.js中配置原生代码包直接拷贝到编译目录中 3、pages.json中配置分包目录,原生入口组件的路径 4、manifest.json中配置分包,使用原生组件 5、需要把原生代码包里的页面修改成组件的方

Java面试八股之怎么通过Java程序判断JVM是32位还是64位

怎么通过Java程序判断JVM是32位还是64位 可以通过Java程序内部检查系统属性来判断当前运行的JVM是32位还是64位。以下是一个简单的方法: public class JvmBitCheck {public static void main(String[] args) {String arch = System.getProperty("os.arch");String dataM

一道经典Python程序样例带你飞速掌握Python的字典和列表

Python中的列表(list)和字典(dict)是两种常用的数据结构,它们在数据组织和存储方面有很大的不同。 列表(List) 列表是Python中的一种有序集合,可以随时添加和删除其中的元素。列表中的元素可以是任何数据类型,包括数字、字符串、其他列表等。列表使用方括号[]表示,元素之间用逗号,分隔。 定义和使用 # 定义一个列表 fruits = ['apple', 'banana

美容美发店营销版微信小程序源码

打造线上生意新篇章 一、引言:微信小程序,开启美容美发行业新纪元 在数字化时代,微信小程序以其便捷、高效的特点,成为了美容美发行业营销的新宠。本文将带您深入了解美容美发营销微信小程序,探讨其独特优势及如何助力商家实现业务增长。 二、微信小程序:美容美发行业的得力助手 拓宽客源渠道:微信小程序基于微信社交平台,轻松实现线上线下融合,帮助商家快速吸引潜在客户,拓宽客源渠道。 提升用户体验:

程序人生--拔丝地瓜

一个会享受生活的人,难免会执迷于探索“三餐茶饭,四季衣裳”的朴素涵义。如今在这繁杂喧闹、竞争激烈的社会环境里,如何才能从周而复始的生活中挖掘出一点儿期待!这是一个仁者见仁智者见智的开放性话题。对于大部分的人来说,看电影、运动、旅游、美食、加班....是假日的备选安排。 春节临走之前,再次尝试“拔丝地瓜”,为何要强调“再次”二字?因为这道甜菜我已经尝试过很多次,失败与成功都经历过。十几年的烧饭经历

vscode python pip : 无法将“pip”项识别为 cmdlet、函数、脚本文件或可运行程序的名称

在vscode中控制台运行python文件出现:无法将"pip”项识别为 cmdlet、函数、脚本文件或可运行程序的名称。 使用vscode开发python,需要安装python开发扩展: 本文已经安装,我们需要找的是python安装所在目录,本文实际路径如下: 如果在本文路径中没有此目录,请尝试在C盘中搜索 python,搜索到相关python目录后,点击Python 3.9进入目录,

2_为MFC程序添加菜单

在MFC中添加菜单栏 1,双击资源文件,显示资源视图,点击Menu插入Menu菜单,编辑菜单的ID,自己取名字。 2,点击“请在此处键入”添加菜单选项,输入&E,E的下面就会产生下划线;在产生的弹出菜单中继续编辑,并且可以添加事件处理函数; 在弹出菜单的任意位置,鼠标右键,弹出的菜单中选择“插入分隔符”,即可产生分隔符 3,在你设计的Dialog窗口的属性栏,选择Menu后面的

在Ubuntu 14.04上安装和配置SNMP守护程序和客户端的方法

前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站。 介绍 作为系统管理员的重要工作之一是收集关于服务器和基础设施的准确信息。有许多工具和选项可用于收集和处理这种类型的信息。其中许多工具都是建立在一种叫做 SNMP 的技术之上。 SNMP 代表简单网络管理协议。它是服务器可以共享关于其当前状态的信息的一种方式,也是管理员可以修改预定义值的通道。虽

第一个PSpice程序

环境cadence 16.6 PSpice A/D PSpice程序开发已经逐渐淡出我们的视线,可是却不能忽视其对电子设计开发的重大作用,在学习的过程中偶然看到PSpice应用,却全部是图形输入,而怀着想知道为什么的好奇心,找遍图书馆唯一一本的PSpice程序设计与仿真的书(虽然也有英文的,但是好几本书,等需要时再看了)终于还是被我找到,经过不断的努力,加上偶然的原因终于成功运行了。 步骤:

hello程序的漫游历程

hello程序的运行过程 #include<stdio.h>int main(){printf("hello, world\n);return 0;} 相信大家都知道这个著名的家伙,hello world,万物起源。 本文的目的就是一起来看看,当这个hello程序在系统上运行时,系统发生了什么以及为什么会这样。 hello程序的生命周期是从一个源文件(源程序)开始的,文件名为hello