编程之美之数独求解器的C++实现方法
编程之美的第一章的第15节。讲的是构造数独。一開始拿到这个问题的确没有思路, 只是看了书中的介绍之后, 发现原来这个的求解思路和N皇后问题是一致的。 可是不知道为啥,反正一開始确实没有想到这个回溯法。知道是用回溯法求解之后。问题就变得easy了非常多。
这里我们不打算实现数独的构造。相反的,我们实现一个数独求解器,以后妈妈再也不用操心我的数独了。
当然求解器的思路和构造数独的思路一样。都是回溯法搜索,这里不再过多说明。
程序执行说明:
1.把待求解的数独数据放到in.txt文件里, 程序会自己主动读取他,并将解输出到屏幕和out.txt文件里。
2.控制台颜色改变 使用了SetConsoleTextAttribute函数。详细使用细节能够參考 C/C++改变控制台输出字体的背景和颜色(windows)
3.关于程序执行时间统计,使用getTickCount()或者clock()都是能够的
执行效果例如以下:
红色表示部分就是求解出来的值了>_<~~
依照惯例以下是源代码:
// ================【shudu.h】===========
#pragma once
#define N 9
#include <fstream>
typedef struct _SearchNode
{
int row;
int col;
int data;
}SearchNode;
class CShuDu
{
public:
CShuDu();
~CShuDu();
void CreateSolution();
private:
bool isOK(int row, int col);
void solve(int searchNode_id);
void writeFile(int id);
void display(int id);
void initShudu();
void output(int id);
private:
int m_shudu[N + 2][N + 1];
bool m_find;
int m_solution_id;
std::fstream outfile;
SearchNode m_searchNode[N * N];
int m_searchLength;
};
// =====================【shudu.cpp】==================
#include <windows.h>
#include "ShuDu.h"
#include <stdio.h>
#include <string.h>
#include <fstream>
#include <iostream>
CShuDu::CShuDu()
{
memset(m_shudu, 0, sizeof(m_shudu));
m_find = false;
m_solution_id = 0;
outfile.open("out.txt", std::ios::out);
m_searchLength = 0;
memset(m_searchNode, 0, sizeof(m_searchNode));
}
CShuDu::~CShuDu()
{
outfile.close();
}
void CShuDu::CreateSolution()
{
initShudu();
solve(1);
}
bool CShuDu::isOK(int row, int col)
{
bool isOK = true;
// 列方向检測
for (int i = 1; i != 10; i++)
{
if (i == row)
continue;
isOK = (m_shudu[i][col] == m_shudu[row][col]) ? false : true;
if (isOK == false)
return isOK;
}
// 行检測
for (int i = 1; i != 10; i++)
{
if (i == col)
continue;
isOK = (m_shudu[row][i] == m_shudu[row][col]) ?
false : true;
if (isOK == false)
return isOK;
}
// 区域检測
int block_start_row = (row - 1) / 3 * 3 + 1;
int block_start_col = (col - 1) / 3 * 3 + 1;
for (int i = block_start_row; i != block_start_row + 3; i++)
{
for (int j = block_start_col; j != block_start_col + 3; j++)
{
if (i == row && j == col)
continue;
isOK = (m_shudu[i][j] == m_shudu[row][col]) ? false : true;
if (isOK == false)
return isOK;
}
}
return isOK;
}
void CShuDu::solve(int searchNode_id)
{
if (m_find == true)
return;
if (m_searchLength + 1 == searchNode_id)
{
//m_find = true;
m_solution_id++;
output(m_solution_id);
return;
}
for (int i = 1; i != 10; i++)
{
int row = m_searchNode[searchNode_id].row;
int col = m_searchNode[searchNode_id].col;
m_shudu[row][col] = i;
if (isOK(row, col))
{
solve(searchNode_id + 1);
row = m_searchNode[searchNode_id + 1].row;
col = m_searchNode[searchNode_id + 1].col;
m_shudu[row][col] = 0;
}
}
}
void CShuDu::display(int id)
{
std::cout << "===========================第" << id << "组数独数据=============================" << std::endl;
system("title 数独求解器 by zhyh2010 version 1.0");
int search_id = 1;
HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
for (int i = 1; i != 10; i++)
{
for (int j = 1; j != 10; j++)
{
if (i == m_searchNode[search_id].row
&& j == m_searchNode[search_id].col)
{
SetConsoleTextAttribute(handle, FOREGROUND_INTENSITY | FOREGROUND_RED);
search_id++;
}
else
SetConsoleTextAttribute(handle, FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_GREEN);
std::cout << m_shudu[i][j] << " ";
}
std::cout << std::endl;
}
std::cout << std::endl;
std::cout << std::endl;
SetConsoleTextAttribute(handle, FOREGROUND_INTENSITY);
}
void CShuDu::writeFile(int id)
{
outfile << "===========================第" << id << "组数独数据=============================" << std::endl;
for (int i = 1; i != 10; i++)
{
for (int j = 1; j != 10; j++)
{
outfile << m_shudu[i][j] << " ";
}
outfile << std::endl;
}
outfile << std::endl;
outfile << std::endl;
}
void CShuDu::output(int id)
{
display(id);
writeFile(id);
//getchar();
}
void CShuDu::initShudu()
{
std::ifstream infile("in.txt");
for (int i = 1; i != 10; i++)
{
for (int j = 1; j != 10; j++)
{
infile >> m_shudu[i][j];
if (m_shudu[i][j] == 0)
{
m_searchLength++;
m_searchNode[m_searchLength].row = i;
m_searchNode[m_searchLength].col = j;
}
}
}
}
// =====================【数独求解器 main.cpp】==================
// @ author : zhyh2010
// @ date : 20150624
// @ version : 1.0
// @ description : C++
// =====================【数独求解器】==================
#include <stdio.h>
#include "ShuDu.h"
#include <time.h>
void main()
{
//DWORD t_start = GetTickCount();
auto t = clock();
CShuDu instance;
instance.CreateSolution();
//DWORD t_end = GetTickCount();
printf("程序执行时间为 %d ms\n", 1000*static_cast<float>(clock() - t)/CLOCKS_PER_SEC);
}
编程之美之数独求解器的C++实现方法的更多相关文章
- 经典数独游戏+数独求解器—纯C语言实现
"心常乐数独小游戏"(下面简称"本软件")是一款windows平台下的数独游戏软件. 本软件是开源.免费软件. 本软件使用纯C语言编写,MinGW编译,NSIS ...
- VBA调用数独求解器
我开发了一个用于求解数独的dll文件,只需要双击一下注册表文件,就可以在VBA中调用这个功能了.具体步骤如下: 下载:https://share.weiyun.com/5dpcNqx 找到ExcelS ...
- JavaScript数独求解器
<html> <head> <style type="text/css"> .txt { width: 50; height: 50; back ...
- C# 数独求解算法。
前言 数独是一种有趣的智力游戏,但是部分高难度数独在求解过程中经常出现大量单元格有多个候选数字可以填入,不得不尝试填写某个数字然后继续推导的方法.不幸的是这种方法经常出现填到一半才发现有单元格无数可填 ...
- SCIP | 数学规划求解器SCIP超详细的使用教程
前言 小伙伴们大家好呀!继上次lp_solve规划求解器的推文出来以后,大家都期待着更多求解器的具体介绍和用法.小编哪敢偷懒,这不,赶在考试周之际,又在忙里偷闲中给大家送上一篇SCIP规划求解的推文教 ...
- java并发编程之美-阅读记录1
1.1什么是线程? 在理解线程之前先要明白什么是进程,因为线程是进程中的一个实体.(线程是不会独立存在的) 进程:是代码在数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,线程则是进程中的 ...
- C#简易一元二次求解器
using System;using System.Collections.Generic;using System.ComponentModel;using System.Data;using Sy ...
- 【编程之美】2.5 寻找最大的k个数
有若干个互不相等的无序的数,怎么选出其中最大的k个数. 我自己的方案:因为学过找第k大数的O(N)算法,所以第一反应就是找第K大的数.然后把所有大于等于第k大的数取出来. 写这个知道算法的代码都花了2 ...
- 【编程之美】CPU
今天开始看编程之美 .第一个问题是CPU的使用率控制,微软的问题果然高大上,我一看就傻了,啥也不知道.没追求直接看答案试了一下.发现自己电脑太好了,4核8线程,程序乱飘.加了一个进程绑定,可以控制一个 ...
随机推荐
- centos6.5图形界面NetworkManager 配置ip文件位置
请教一个关于网络配置的问题,如图:该网络连接图形界面中 有2个配置,其中System eth0 有对应的配置文件/etc/sysconfig/network-scripts/ifcfg-eth0,但是 ...
- 忘记linux密码
http://blog.163.com/xygzlyq@126/blog/static/22585899200810471512530/
- nginx+redis 实现 jsp页面缓存,提升系统吞吐率
最近在开发的时候,发现之前APP客户端的一部分页面用的是webview交互,这些页面请求很多,打开一套试卷,将会产生100+的请求量,导致系统性能下降.于是考虑在最靠近客户端的Nginx服务器上做Re ...
- Linux内核中常见内存分配函数(一)
linux内核中采 用了一种同时适用于32位和64位系统的内存分页模型,对于32位系统来说,两级页表足够用了,而在x86_64系 统中,用到了四级页表. * 页全局目录(Page Global Dir ...
- andengine游戏引擎总结进阶篇2
本篇包括瓦片地图,物理系统, 1瓦片地图 超级玛丽,冒险岛,魂斗罗等游戏主场景都有瓦片地图画成,它的作用可见一斑,它可以用tiled Qt软件画成,在辅助篇中讲讲解tiled Qt软件的使用 1)加载 ...
- LA - 5031 - Graph and Queries
题意:一个N个点(编号从1开始),M条边的无向图(编号从1开始),有3种操作: D X:把编号为X的边删了: Q X K:查询编号为X的结点所在连通分量第K大的元素: C X V:将编号为X的结点的权 ...
- 【Andord真】SlideMenu+ViewPagerIndictor双滑动边栏+滑动导航条
采取SlideMenu达到的效果侧边栏: 间 setContentView是设置主背景的布局 setBehindContentView是设置左边菜单的布局 setSecondaryMenu是设置右边的 ...
- Spire PDF for .NET 在ASP.NET中的使用 ---- 并非那么“美好”,有些挫折!
笔者注:看此文前,请您先看一下上一篇文章吧. 昨天的时候,我测试了一下Spire PDF在WinForm程序中的应用,可以说用起来很简单(请忽略效率问题,没有进行测试).不过在互联网如此发达的今天,适 ...
- C++学习笔录3
1.隐藏:存在于派生类和基类中.只要成员名字相同就叫做隐藏.参数和函数名都相同时,是一种特殊的隐藏,叫做重写,重写只出现在函数中.若需要访问基类中被隐藏的成员,必须访问这种方法:“对象名:类名::隐藏 ...
- MySQL函数笔记
MySQL函数笔记 日期函数 SELECT t1.xcjyrq, t1.* FROM view_sbxx t1 WHERE t1.syzt ; SELECT t1.xcjyrq, t1.* FROM ...