下面这个代码是生成一个数独题目(58空格),有时能生产,有时则出现错误。
#include <iostream>
#include <cstdlib>
#include <ctime>
#include<time.h>
#include<fstream>
#define BLANKS 58
#define FAIL 50
using namespace std;
int table[9][9],solves=0,nothing[162+1],n_sub=1;
fstream out_stream;
void shuffle(int arr[], int n);
bool test(int x, int y, int v);
bool put(int line, int index);
bool put_line(int line);
bool test();
void print_all();
void dfs();
int check(int y,int x,int *mark) ; //求probable[y][x] 并且mark[]中为0的元素说明可以试探
int solve();
bool create_game(int blanks);
void print_all(int k); //输出到文件
void shuffle(int arr[], int n)
{
int tmp, rd;
for(int i = 0; i < n; i++)
{
rd = rand() % 9;
tmp = arr[rd];
arr[rd] = arr[i];
arr[i] = tmp;
}
}
bool test(int x, int y, int v)
{
int _x = x / 3 * 3;
int _y = y / 3 * 3;
for(int i = _x; i < _x + 3; i++) //测试3 * 3矩阵内是否有重复的数
{
for(int j = _y; j < _y + 3; j++)
{
if(table[i][j] == v)
{
return false;
}
}
}
for(int i = 0; i < 9; i++) //测试横向、纵向是否有重复的数
{
if(table[x][i] == v || table[i][y] == v)
return false;
}
return true;
}
bool put(int line, int index)
{
if(index > 8)
return true;
int num[] = {1,2,3,4,5,6,7,8,9};
//打乱当前准备写入数字的前后顺序
shuffle(num, 9);
for(int i = 0; i < 9; i++)
//测试数字是否允许填入当前方格
if( test(line, index, num[i]) == true )
{
table[line][index] = num[i];
//填入成功则处理下一个方格
if( put(line, index + 1) == true )
{
return true;
}
}
table[line][index] = 0; //失败后复位
return false;
}
bool put_line(int line)
{
if(line > 8)
return true;
if( put(line, 0) == true )
//当前一行添入完成后,进入下一行再重复处理。
if( put_line(line + 1) == true )
return true;
for(int i = 0; i < 9; i++)
table[line][i] = 0;
return false;
}
void print_all()
{
cout<<"print storage"<<endl;
for(int i=1;i<=9;i++)
{
for(int j=1;j<=9;j++)
{
cout<<table[i-1][j-1]<<" ";
if(j%3==0) cout<<" ";
}
cout<<endl;
if(i%3==0) cout<<endl;
}
cout<<endl<<endl;
}
void dfs()
{
int i,j,im=-1,jm,min=10;
int mark[10];
for(i=0;i<9;++i)
for(j=0;j<9;++j)
{
if(table[i][j])
continue;
int c=check(i,j,mark);
if(c==0)
return;
if(c<min)
{
im=i;
jm=j;
min=c;
}
}
if(im==-1)
{
solves++;
if(solves==2)
throw(1); //如果解法不唯一,不会等到所有解都出来才结束运行, 保留下面的return又能确定是不是只有唯一解。
return;
}
check(im,jm,mark);
for(i=1;i<=9;++i)
if(mark[i]==0)
{
table[im][jm]=i;
dfs();
}
table[im][jm]=0;
}
int solve()
{
try
{
dfs();
solves=0; //调试后发现
return(1);
}
catch(int)
{
solves=0; //调试后发现,solves是全局变量,以后solves越来越大永远不可能等于2
return(2);
}
}
int check(int y,int x,int *mark) //求probable[y][x]
{
int i,j,is,js,count=0;
for(i=1;i<=9;++i)
mark[i]=0;
for(i=0;i<9;++i)
mark[table[y][i]]=1;
for(i=0;i<9;++i)
mark[table[i][x]]=1;
is=y/3*3;
js=x/3*3;
for(i=0;i<3;++i)
for(j=0;j<3;++j)
mark[table[is+i][js+j]]=1;
for(i=1;i<=9;++i)
if(mark[i]==0)
count++;
return count;
}
bool create_game(int blanks)
{
int i,k,row=100,col,tmp;
srand(time(0));
for( i=1;i<=blanks;i++)
{
if(i==58)
system("pause");
int num=0;
do
{
if(row!=100)
if(table[row][col]!=0)
{
nothing[n_sub-1]=nothing[n_sub-2]=0;
for(int j=1;j<=(n_sub-3)/2;j++)
table[nothing[2*j-1]][nothing[2*j]]=0;
n_sub-=2;
}
do
{
k=rand()%81;
row=k/9 ;
col=k-9*row;
tmp=table[row][col];
}while(tmp==0);
table[row][col]=0;
nothing[n_sub++]=row; nothing[n_sub++]=col;
num++;
if(num==FAIL)
{
for(int i=0;i<=n_sub-1;i++)
nothing[i]=0;
return(false);
}
}while((solve()==2)? table[row][col]=tmp : 0);
}
if(i==blanks+1)
return (true);
}
void create_gameover()
{
for(int i=0;i<9;i++)
for(int j=0;j<9;j++)
table[i][j]=0;
for(int i = 0; i < 9; i++)
table[0][i] = i + 1;
srand((unsigned int)time(NULL));
shuffle(table[0], 9);
//从第二行开始添入数字
while(!put_line(1)) ;
}
void print_all(int k)
{
for(int i=1;i<=9;i++)
{
for(int j=1;j<=9;j++)
{
out_stream<<table[i-1][j-1]<<" ";
if(j%3==0) out_stream<<" ";
}
out_stream<<endl;
if(i%3==0) out_stream<<endl;
}
out_stream<<endl<<endl;
}
int main()
{
long time1=clock();
create_gameover();
while(!create_game(BLANKS))
create_gameover();
print_all();
out_stream.open("d:\\c++\\数独12\\question\\生成题2.txt");
print_all(1);
out_stream.close();
time1=clock()-time1;
cout<<"use time "<<time1/1000<<"s"<<time1%1000<<"ms"<<endl;
system("pause");
}
下面这个代码是生产一个16*16终盘,有时正确,有时错误,错误同样是有未经处理异常,访问冲突。
#include<cstdlib>
#include<time.h>
#include<iostream>
using namespace std;
int count=0,vessel[362880][16];
int b[16]={1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16},m=0;
int data[16][16],data1[16][16];
int line[16][16], column[16][16], block[16][16];
int Initial(int i, int j, int start);
void shuffle(int arr[]);
void move1(int list[],int a,int b);
void move2(int list[],int a,int b);
void Perm(int list[], int s, int e) ;
void move1(int list[],int a,int b)
{
int tmp=*(list+b);
for(int i=b-1;i>=a;i--)
*(list+i+1)=*(list+i);
*(list+a)=tmp;
}
void move2(int list[],int a,int b)
{
int tmp=*(list+a);
for(int i=a+1;i<=b;i++)
*(list+i-1)=*(list+i);
*(list+b)=tmp;
}
void Perm(int list[], int s, int e) //对list[k]——list[m]进行全排列(可以有重复元素)
{ //这里可以改动成对k到m的奇数(偶数引申到给出一个公式即一种顺序)下标进行排列
if(s>e)
{
for(int k=0;k<=15;k++)
vessel[count][k]=list[k];
count++;
if(count==362880) return;
}
for (int i=s; i <= e; i++)
{
move1(list,s,i);
Perm(list,s+1,e);
if(count==362880) return;
move2(list,s,i);
}
}
void shuffle(int arr[])
{
int tmp, rd;
for(int i = 0; i <=15 ; i++)
{
rd = rand() % 16;
tmp = arr[rd];
arr[rd] = arr[i];
arr[i] = tmp;
}
}
int Initial(int i, int j, int start)
{
//if(i==8)
//system("pause");
int k;
for (k = start;k>=0;k--) //从1至9依次试验
{
if (!line[i][b[k]-1] && !column[j][b[k]-1] && !block[i/4*4+j/4][b[k]-1])
{
data[i][j] = b[k];
data1[i][j]=k;
line[i][b[k]-1] = 1;
column[j][b[k]-1] = 1;
block[i/4*4+j/4][b[k]-1] = 1;
if (i == 15 && j == 15) //初始化完毕退出
{
return(1);
}
if (j == 15) //定位下一位置
{
j = 0;
i++;
if(i==4)
{
int mm=rand()%362880;
for(int j=0;j<=15;j++)
b[j]=vessel[mm][j];
}
if(i==8)
{
int mm=rand()%362880;
for(int j=0;j<=15;j++)
b[j]=vessel[mm][j];
}
if(i==12)
{
int mm=rand()%362880;
for(int j=0;j<=15;j++)
b[j]=vessel[mm][j];
}
}
else
j++;
Initial(i, j, 15); //初始化下一位置
return 1;
}
if (k == 0) //1至9均无合适值,回溯
{
do
{
if (j == 0) //定位前一位置
{
j = 15;
i--;
}
else
j--;
line[i][data[i][j]-1] = 0;
column[j][data[i][j]-1] = 0;
block[i/4*4+j/4][data[i][j]-1] = 0;
}while (data[i][j] == b[0]);
//回溯到一可以继续的位置,从这一位置开始递归赋值
Initial(i, j, data1[i][j] -1);
return 1; //递归结束返回后立即退出
}
}//for
}
int main()
{
int i, j;
long time1;
time1=clock();
Perm(b,0,15);
srand(time(0));
for(int u=1;u<=100;u++)
{
shuffle(b);
Initial(0,0,15);
for(int i=0;i<=15;i++)
for(int j=0;j<=15;j++)
{
data[i][j]=0;
data1[i][j]=0;
line[i][j]=0;
column[i][j]=0;
block[i][j]=0;
}
}
printf("%ums\n",clock()-time1);
for (i = 0; i < 16; i++)
{
for (j = 0; j < 16; j++)
printf("%i ", data[i][j]);
printf("\n");
}
system("pause");
}