P1784 数独(洛谷)

这篇文章展示了如何使用C++编程语言解决难度极高的数独问题,通过数据结构和逻辑判断来填充数独,实现自动求解。
摘要由CSDN通过智能技术生成

(1)题目

来源

数独 - 洛谷

题目描述

数独是根据 9×9 盘面上的已知数字,推理出所有剩余空格的数字,并满足每一行每一列每一个粗线宫内的数字均含 1−9 ,不重复。每一道合格的数独谜题都有且仅有唯一答案,推理方法也以此为基础,任何无解或多解的题目都是不合格的。

芬兰一位数学家号称设计出全球最难的“数独游戏”,并刊登在报纸上,让大家去挑战。

这位数学家说,他相信只有“智慧最顶尖”的人才有可能破解这个“数独之谜”。

据介绍,目前数独游戏的难度的等级有一到五级,一是入门等级,五则比较难。不过这位数学家说,他所设计的数独游戏难度等级是十一,可以说是所以数独游戏中,难度最高的等级。他还表示,他目前还没遇到解不出来的数独游戏,因此他认为“最具挑战性”的数独游戏并没有出现。

输入格式

一个未填的数独。

输出格式

填好的数独。

输入样例

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

输出样例

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

(2)思路

1.分析问题:分析已知和未知

本题难点在于标记已填过的数字,并确保每行每列每九宫格中数字不重样

标记行和列较为简单,第1个维度保存行数/列数,第2个维度保存填的数字

标记九宫格中数字较难,需要找规律

我们将九宫格画出来,并标上号,建立一个平面直角坐标系。

我们只要让每个九宫格里所有位置的坐标(粉色)都在九宫格的坐标(橙色)内,就可以了

找规律发现,(行坐标+2)/3==九宫格行坐标,(列坐标+2)/3==九宫格列坐标

试验一下:

(2.3)数字7,(2+2)/3=1,(3+2)/3=1,在(1,1)九宫格里

各位可以自行试一试

注意:若此方法太难理解,可以写9个判断来找这个数在哪个九宫格里

2.数据定义:已知和未知的取名和类型

a[10][10]:保存数独中的数

k:暂时保存相应a[i][j]所保存的数

f1[10][10]:标记每行中每个数字是否出现

f2[10][10]:标记每列中每个数字是否出现

f3[5][5][10]:标记每九宫格中每个数字是否出现

3.数据输入:输入已知 

输入时标记,若有数,标记此行此列此九宫格中这个数字;若是0,标记也无妨(填入数字为1-9)

    for(int i=1;i<=9;i++)
    {
        for(int j=1;j<=9;j++)
        {
            cin>>a[i][j];
            k=a[i][j];
            f1[i][k]=1;//标记
            f2[j][k]=1;
            f3[(i+2)/3][(j+2)/3][k]=1;
        }
    }

4.数据计算:数字建模+设计算法(函数部分)----x=行,y=列

先判断这个数独是否被填完,若填完则直接输出并结束程序(题目说有且仅有唯一答案)

再判断是否需要换行

然后判断这个位置有没有填数

    if(x==9&&y==10)
    {
        for(int i=1;i<=9;i++)
        {
            for(int j=1;j<=9;j++) cout<<a[i][j]<<" ";//输出
            cout<<endl;
        }
        exit(0);//结束所有函数
    }
    if(y==10) f(x+1,1);
    if(a[x][y]!=0) f(x,y+1);

若没有,枚举1-9这些数,判断此行此列此九宫格中是否有这个数,没有则填数并标记

然后进行下一层

若下一层进行后返回了,说明此数不应填在此位置,清空标记,并若这个位置的数为0

    else
    {
        for(int i=1;i<=9;i++)
        {
            if(f1[x][i]==0&&f2[y][i]==0&&f3[(x+2)/3][(y+2)/3][i]==0)
            {
                a[x][y]=i;//填数
                f1[x][i]=1;f2[y][i]=1;f3[(x+2)/3][(y+2)/3][i]=1;//标记
                f(x,y+1);//进行下一层
                a[x][y]=0;//清标记
                f1[x][i]=0;f2[y][i]=0;f3[(x+2)/3][(y+2)/3][i]=0;
            }
        }
     }

(3)完整AC代码

#include<iostream>
using namespace std;
int a[10][10],f1[10][10],f2[10][10],f3[5][5][10];
void f(int x,int y)
{
	if(x==9&&y==10)
	{
		for(int i=1;i<=9;i++)
		{
			for(int j=1;j<=9;j++) cout<<a[i][j]<<" ";
			cout<<endl;
		}
		exit(0);
	}
	if(y==10) f(x+1,1);
	if(a[x][y]!=0) f(x,y+1);
	else
	{
		for(int i=1;i<=9;i++)
		{
			if(f1[x][i]==0&&f2[y][i]==0&&f3[(x+2)/3][(y+2)/3][i]==0)
			{
				a[x][y]=i;
				f1[x][i]=1;f2[y][i]=1;f3[(x+2)/3][(y+2)/3][i]=1;
				f(x,y+1);
				a[x][y]=0;
				f1[x][i]=0;f2[y][i]=0;f3[(x+2)/3][(y+2)/3][i]=0;
			}
		}
	 } 
	
}
int main()
{
	int k;
	for(int i=1;i<=9;i++)
	{
		for(int j=1;j<=9;j++)
		{
			cin>>a[i][j];
			k=a[i][j];
			f1[i][k]=1;
			f2[j][k]=1;
			f3[(i+2)/3][(j+2)/3][k]=1;
		}
	}
	f(1,1);
	return 0;
 } 

  • 15
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值