蒟蒻用c++搓出了可视化数独求解!

1.数独是?

数独(Sudoku)是一种逻辑填数字游戏,目标是在9×9的格子中填入数字1至9,满足以下规则:

  • 每一行包含1至9的所有数字且不重复。
  • 每一列包含1至9的所有数字且不重复。
  • 每个3×3的小宫(共9个)包含1至9的所有数字且不重复。

游戏开局时部分格子已预先填入数字(称为“提示数”),玩家需通过逻辑推理填补剩余空格。

2.数独和我

我发现了一道题目:P1784 数独 - 洛谷

我自然而然的萌生出做一个可视化解题代码的想法,后来发现能通过原题的代码加上输出后,速度太慢,于是进行了性能优化。代码如下:

#include <bits/stdc++.h>
#include <windows.h>
using namespace std;
int a[10][10],p,cnt,b[10][10];
struct node{
	int x,y,num;
	friend bool operator <(node u1,node u2){
		return u1.num>u2.num;
	}
}a0[100];
bool pri,h[10][10],l[10][10],jgg[10][10];
void resort(int pos){
	for(int i=pos;i<=p;i++){
		int n;
		if(a0[i].x<=3)
			n=0;
		else if(a0[i].x<=6)
			n=3;
		else n=6;
		if(a0[i].y<=3)
			n++;
		else if(a0[i].y<=6)
			n+=2;
		else n+=3;
		a0[i].num=0;
		for(int j=1;j<=9;j++)
			a0[i].num+=(h[a0[i].x][j]||l[a0[i].y][j]||jgg[n][j]);
	}
	sort(a0+pos,a0+p+1);
}
void dfs(int pos){
	if(pos>p){
		pri=1;
		return;
	}
	int n;
	if(a0[pos].x<=3)
		n=0;
	else if(a0[pos].x<=6)
		n=3;
	else n=6;
	if(a0[pos].y<=3)
		n++;
	else if(a0[pos].y<=6)
		n+=2;
	else n+=3;
	int m=-1;
	for(int i=1;i<=9;i++){
		if(h[a0[pos].x][i]||l[a0[pos].y][i]||jgg[n][i])
			continue;
		h[a0[pos].x][i]=l[a0[pos].y][i]=jgg[n][i]=1;
		a[a0[pos].x][a0[pos].y]=i;
		m=++cnt;
		cout<<"当("<<a0[pos].x<<','<<a0[pos].y<<")位置为"<<i<<"时("<<m<<"):{\n";
		resort(pos+1);
		dfs(pos+1);
		if(pri)
			return;
		cout<<"}("<<m<<")\n";
		h[a0[pos].x][i]=l[a0[pos].y][i]=jgg[n][i]=0;
		resort(pos+1);
	}
	if(m==-1)
		cout<<'('<<a0[pos].x<<','<<a0[pos].y<<")位置没有可行的解。\n";
}
int main(){
	cout<<"欢迎使用可解释型数独填充器,请填入9X9矩阵,0表示待定。\n";
	for(int i=1;i<=9;i++)
		for(int j=1;j<=9;j++){
			cin>>a[i][j];
			b[i][j]=a[i][j];
			int n;
			if(i<=3)
				n=0;
			else if(i<=6)
				n=3;
			else n=6;
			if(j<=3)
				n++;
			else if(j<=6)
				n+=2;
			else n+=3;
			if(!a[i][j]){
				a0[++p].x=i;
				a0[p].y=j;
				continue;
			}
			if(h[i][a[i][j]]||l[j][a[i][j]]||jgg[n][a[i][j]]){
				cout<<"警告:此矩阵无解!";
				getchar();
			}
			h[i][a[i][j]]=l[j][a[i][j]]=jgg[n][a[i][j]]=1;
		}
	resort(1);
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	cout<<"好的,推理开始。首先";
	dfs(1);
	cout<<"整图恰好被填满。\n因此,以上是全部过程。结果为:\n";
	for(int i=1;i<=9;i++){
		for(int j=1;j<=9;j++)
			cout<<a[i][j]<<' ';
		cout<<'\n';
	}
	cout<<"复杂分数:"<<cnt;
	return 0;
}

中心思路就是暴力的去试数,但是优化的地方在于寻找方案最少的位置进行尝试,大大压缩了时间复杂度,支持大常数的输出。

可以看出,代码长度对于竞赛题目来说过于冗长,如果大佬有改进和进一步优化的方案,或是大家对此项目有自己的感想,欢迎评论区见!

征求:最复杂的数独题目。您可以运行代码,输入您的数独题目,并查看难度分数,争取打破纪录。蒟蒻在评论区静候。

目前记录:

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

难度分数:9133

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值