C++实现数独(附带过程)

首先,来到这里的人应该都知道数独是什么。

那么,如果没有c++,你,在面对数独时会怎么做?

1.纯方法

1.摒除法:用数字去找单元内唯一可填空格,称为摒除法,数字可填唯一空格称为摒余解(隐性唯一解)。

就是通过某一个格子所在行与列和宫,确定当前格子上的数:

1 3 4
5(x) 5(x) 5(x) 5
5(x) 5(x) 5
5 5

根据已知三个“5”,排除一宫8个格子,得到“5”的掘除法

#ifndef SHUDUFA_H
#define SHUDUFA_H//定义头文件
#include
using namespace std;
typedef pair P; P ji[11];
int kuai[11][11],lie[11][11],hang[11][11],ma[11][11],k,mm[11][11];
inline int d(int pd,int x,int y) {if(pd==1) return x; else return y;}
inline int find(int num)
{
	int jinum=0;
	for(int i=1;i<=9;i++) for(int j=1;j<=9;j++) if(ma[i][j]==num) ji[++jinum]=P(i,j);
	return jinum;
}//find(i)表示寻找数独上所有i数字的坐标并存于ji[i]中。
inline void biao_hui(int p,int x,int y,int val,int howk)
{
	hang[x][val]=p;
	lie[y][val]=p;
	kuai[howk][val]=p;
	mm[x][y]=1;
	ma[x][y]=p*val;
	k+=2*p-1;
}//biao_hui(p,x,y,val,howk)表示将数独第(x,y)个格子填入val且仅当p=1,标记(p=0时为回溯)
inline void does(int i1,int i2,int j1,int j2,int temp[11][11],int num,int howk)
{
	int sum=0,x,y; 
	for(int i=i1;i<=i2;i++)
	{
		for(int j=j1;j<=j2;j++)
		{
			if(temp[i][j]) sum++;
			else x=i,y=j;
		}
	}
	if(sum==8&&kuai[howk][num]==0) biao_hui(1,x,y,num,howk);//宫内唯一解
}
inline void tian(int shu,int num)
{
	int temp[11][11];
	for(int j=1;j<=9;j++) for(int kk=1;kk<=9;kk++) temp[j][kk]=mm[j][kk];//记录那些位置没填,temp与mm此处功能一样。
	for(int i=1;i<=shu;i++)
	{
		int x=ji[i].first,y=ji[i].second;
		for(int j=1;j<=9;j++) temp[x][j]=temp[j][y]=1;
	}//将数字num用于行列摒除法,再找宫内唯一解。
	for(int i=1;i<=3;i++)
	{
		int xr=i*3,xl=xr-2;
		for(int j=1;j<=3;j++) does(xl,xr,(j-1)*3+1,j*3,temp,num,(i-1)*3+j);//找宫内唯一解并填入(上转does)
	}
}
inline void does2(int pd)//pd=1为求行内唯一解,pd=2为求列内唯一解
{
	if(pd==0)
	{
		for(int i=1;i<=9;i++) tian(find(i),i);
		return;
	}
	for(int i=1;i<=9;i++)
	{
		queue q;
		int use[11],bu=0;
		memset(use,0,sizeof(use)); 
		for(int j=1;j<=9;j++)
		{
			if(!hang[d(pd,i,j)][d(pd,j,i)])
			{
				q.push(d(pd,j,i));
				use[d(pd,j,i)]=1;
				bu++;
			}
		}
		for(int j=1;j<=9;j++)
		{
			if(ma[d(pd,i,j)][d(pd,j,i)]) continue;
			int num=(d(pd,i,j)-1)/3*3+(d(pd,j,i)-1)/3+1;
			for(int ki=1;ki<=9;ki++)
			{
				if(use[ki])
				{
					int uu=0;
					for(int kk=1;kk<=9;kk++)
					{
						if(use[kk]&&ki!=kk)
						{
							if(kuai[num][kk]||hang[d(pd,i,j)][kk]||lie[d(pd,j,i)][kk]) uu++;
						}
					}
					if(uu==bu-1&&!kuai[num][ki]&&!hang[d(pd,i,j)][ki]&&!lie[d(pd,j,i)][ki])
					{
						bu--;
						use[ki]=0;
						biao_hui(1,d(pd,i,j),d(pd,j,i),ki,num);
					}
				}
			}
		}
	}
} 
#endif 

2.余数法:用格位去找唯一可填数字,称为余数法,格位唯一可填数字称为唯余解(Naked Single)。(这简单,不用赘述)

3.直观法:不做任何记号,直接从数独的盘势观察线索,推论答案的方法。蒙圈......

4.候选数法就是删减等位群格位已出现的数字,将剩余可填数字填入空格做为解题线索的参考,可填数字称为候选数(Candidates,或称备选数)。(好恐怖)

2.c++思想:

1.暴力搜索

​
inline void dfs(int nx,int ny)
{
	if(ma[nx][ny]) 
	{
		if(ny==9)
		{
			if(nx<9) dfs(nx+1,1);
			else return;
		}
		else dfs(nx,ny+1);
		return;
	}
	for(int i=1;i<=9;i++)
	{
		if(hang[nx][i]||lie[ny][i]||kuai[((nx-1)/3*3+(ny-1)/3+1)][i]) continue;
		biao_hui(1,nx,ny,i,((nx-1)/3*3+(ny-1)/3+1));
		if(k==81)
		{
			print(ma);
			continue;
		}
		if(ny==9)
		{
			if(nx<9) dfs(nx+1,1);
			else continue;
		}
		else dfs(nx,ny+1);
		biao_hui(0,nx,ny,i,((nx-1)/3*3+(ny-1)/3+1));
	}
}

​

2.使用上述方法

#ifndef SHUDUFA_H
#define SHUDUFA_H
#include
using namespace std;
typedef pair P; P ji[11];
int kuai[11][11],lie[11][11],hang[11][11],ma[11][11],k,mm[11][11];
inline int d(int pd,int x,int y) {if(pd==1) return x; else return y;}
inline int find(int num)
{
	int jinum=0;
	for(int i=1;i<=9;i++) for(int j=1;j<=9;j++) if(ma[i][j]==num) ji[++jinum]=P(i,j);
	return jinum;
}
inline void biao_hui(int p,int x,int y,int val,int howk)
{
	hang[x][val]=p;
	lie[y][val]=p;
	kuai[howk][val]=p;
	mm[x][y]=1;
	ma[x][y]=p*val;
	k+=2*p-1;
}
inline void does(int i1,int i2,int j1,int j2,int temp[11][11],int num,int howk)
{
	int sum=0,x,y; 
	for(int i=i1;i<=i2;i++)
	{
		for(int j=j1;j<=j2;j++)
		{
			if(temp[i][j]) sum++;
			else x=i,y=j;
		}
	}
	if(sum==8&&kuai[howk][num]==0) biao_hui(1,x,y,num,howk);
}
inline void tian(int shu,int num)
{
	int temp[11][11];
	for(int j=1;j<=9;j++) for(int kk=1;kk<=9;kk++) temp[j][kk]=mm[j][kk];
	for(int i=1;i<=shu;i++)
	{
		int x=ji[i].first,y=ji[i].second;
		for(int j=1;j<=9;j++) temp[x][j]=temp[j][y]=1;
	}
	for(int i=1;i<=3;i++)
	{
		int xr=i*3,xl=xr-2;
		for(int j=1;j<=3;j++) does(xl,xr,(j-1)*3+1,j*3,temp,num,(i-1)*3+j);
	}
}
inline void does2(int pd)
{
	if(pd==0)
	{
		for(int i=1;i<=9;i++) tian(find(i),i);
		return;
	}
	for(int i=1;i<=9;i++)
	{
		queue q;
		int use[11],bu=0;
		memset(use,0,sizeof(use)); 
		for(int j=1;j<=9;j++)
		{
			if(!hang[d(pd,i,j)][d(pd,j,i)])
			{
				q.push(d(pd,j,i));
				use[d(pd,j,i)]=1;
				bu++;
			}
		}
		for(int j=1;j<=9;j++)
		{
			if(ma[d(pd,i,j)][d(pd,j,i)]) continue;
			int num=(d(pd,i,j)-1)/3*3+(d(pd,j,i)-1)/3+1;
			for(int ki=1;ki<=9;ki++)
			{
				if(use[ki])
				{
					int uu=0;
					for(int kk=1;kk<=9;kk++)
					{
						if(use[kk]&&ki!=kk)
						{
							if(kuai[num][kk]||hang[d(pd,i,j)][kk]||lie[d(pd,j,i)][kk]) uu++;
						}
					}
					if(uu==bu-1&&!kuai[num][ki]&&!hang[d(pd,i,j)][ki]&&!lie[d(pd,j,i)][ki])
					{
						bu--;
						use[ki]=0;
						biao_hui(1,d(pd,i,j),d(pd,j,i),ki,num);
					}
				}
			}
		}
	}
} 
#endif 

3.完整代码:

cpp:

#include"bits/stdc++.h"
#include"shudufa.h"
#include"reawri.h"
using namespace std;
inline void dfs(int nx,int ny)
{
	if(ma[nx][ny]) 
	{
		if(ny==9)
		{
			if(nx<9) dfs(nx+1,1);
			else return;
		}
		else dfs(nx,ny+1);
		return;
	}
	for(int i=1;i<=9;i++)
	{
		if(hang[nx][i]||lie[ny][i]||kuai[((nx-1)/3*3+(ny-1)/3+1)][i]) continue;
		biao_hui(1,nx,ny,i,((nx-1)/3*3+(ny-1)/3+1));
		if(k==81)
		{
			print(ma);
			continue;
		}
		if(ny==9)
		{
			if(nx<9) dfs(nx+1,1);
			else continue;
		}
		else dfs(nx,ny+1);
		biao_hui(0,nx,ny,i,((nx-1)/3*3+(ny-1)/3+1));
	}
}
inline void work()
{
	int t=0;string a,b;
	while(k<81)
	{
		if(t==0) a="(区域确定式)",b="(横线确定式)";
		if(t==1) a="(横线确定式)",b="(竖线确定式)";
		int lastk=k;
		for(int i=0;i<=t;i++) does2(t);
		if(lastk==k)
		{
			print(ma);
			cout<<("仅有"+a+"法不可行\n加入法"+b+"\n");
			t++;
		}
		if(t>2) break;
	}
	cout<<"不正常方法:开始搜索......\n";
	dfs(1,1);
}
int main()
{
	read();
	work();
	return 0;
} 

shudufa.h:

#ifndef SHUDUFA_H
#define SHUDUFA_H
#include
using namespace std;
typedef pair P; P ji[11];
int kuai[11][11],lie[11][11],hang[11][11],ma[11][11],k,mm[11][11];
inline int d(int pd,int x,int y) {if(pd==1) return x; else return y;}
inline int find(int num)
{
	int jinum=0;
	for(int i=1;i<=9;i++) for(int j=1;j<=9;j++) if(ma[i][j]==num) ji[++jinum]=P(i,j);
	return jinum;
}
inline void biao_hui(int p,int x,int y,int val,int howk)
{
	hang[x][val]=p;
	lie[y][val]=p;
	kuai[howk][val]=p;
	mm[x][y]=1;
	ma[x][y]=p*val;
	k+=2*p-1;
}
inline void does(int i1,int i2,int j1,int j2,int temp[11][11],int num,int howk)
{
	int sum=0,x,y; 
	for(int i=i1;i<=i2;i++)
	{
		for(int j=j1;j<=j2;j++)
		{
			if(temp[i][j]) sum++;
			else x=i,y=j;
		}
	}
	if(sum==8&&kuai[howk][num]==0) biao_hui(1,x,y,num,howk);
}
inline void tian(int shu,int num)
{
	int temp[11][11];
	for(int j=1;j<=9;j++) for(int kk=1;kk<=9;kk++) temp[j][kk]=mm[j][kk];
	for(int i=1;i<=shu;i++)
	{
		int x=ji[i].first,y=ji[i].second;
		for(int j=1;j<=9;j++) temp[x][j]=temp[j][y]=1;
	}
	for(int i=1;i<=3;i++)
	{
		int xr=i*3,xl=xr-2;
		for(int j=1;j<=3;j++) does(xl,xr,(j-1)*3+1,j*3,temp,num,(i-1)*3+j);
	}
}
inline void does2(int pd)
{
	if(pd==0)
	{
		for(int i=1;i<=9;i++) tian(find(i),i);
		return;
	}
	for(int i=1;i<=9;i++)
	{
		queue q;
		int use[11],bu=0;
		memset(use,0,sizeof(use)); 
		for(int j=1;j<=9;j++)
		{
			if(!hang[d(pd,i,j)][d(pd,j,i)])
			{
				q.push(d(pd,j,i));
				use[d(pd,j,i)]=1;
				bu++;
			}
		}
		for(int j=1;j<=9;j++)
		{
			if(ma[d(pd,i,j)][d(pd,j,i)]) continue;
			int num=(d(pd,i,j)-1)/3*3+(d(pd,j,i)-1)/3+1;
			for(int ki=1;ki<=9;ki++)
			{
				if(use[ki])
				{
					int uu=0;
					for(int kk=1;kk<=9;kk++)
					{
						if(use[kk]&&ki!=kk)
						{
							if(kuai[num][kk]||hang[d(pd,i,j)][kk]||lie[d(pd,j,i)][kk]) uu++;
						}
					}
					if(uu==bu-1&&!kuai[num][ki]&&!hang[d(pd,i,j)][ki]&&!lie[d(pd,j,i)][ki])
					{
						bu--;
						use[ki]=0;
						biao_hui(1,d(pd,i,j),d(pd,j,i),ki,num);
					}
				}
			}
		}
	}
} 
#endif 

reawri.h:

#ifndef REAWRI_H
#define REAWRI_H
#include"shudufa.h"
#include
using namespace std;
inline void print(int mmm[11][11])
{
	for(int i=1;i<=9;i++)
	{
		for(int j=1;j<=9;j++) cout<>ma[i][j];
			if(ma[i][j]) 
			{
				int num=(i-1)/3*3+(j-1)/3+1;
				biao_hui(1,i,j,ma[i][j],num);
			}
		}
	}
}
#endif

你可能感兴趣的:(模拟,c++)