欢迎吹毛求疵 QQ:1423173783 邮箱:1423173783@qq.com
这个代码是我做事时脑中突然递归到这里,才贴出来的。我认为有必要把调试遇到的错误的特例贴出来。 代码没做啥美观修饰,抱歉,本来就是递归到这
我想马上,返回那里还有一些问题没解决。
#include <iostream>
#include <cstdlib>
#include <ctime>
#include<time.h>
#include<cstdlib>
#define K 4
using namespace std;
int table[K*K][K*K];
void shuffle(int arr[])
{
int tmp, rd;
for(int i = 0; i < K*K; i++)
{
rd = rand() % (K*K);
tmp = arr[rd];
arr[rd] = arr[i];
arr[i] = tmp;
}
}
bool test(int x, int y, int v)
{
int _x = x / K * K;
int _y = y / K * K;
//测试3 * 3矩阵内是否有重复的数
for(int i = _x; i <=x-1; i++)
for(int j = _y; j <= _y + K-1; j++)
if(table[i][j] == v) return false;
//测试横向、纵向是否有重复的数
for(int j = 0; j <=y-1; j++)
if(table[x][j] == v ) return false;
for(int i=0;i<=x-1;i++)
if(table[i][y]==v) return (false);
return true;
}
int main()
{
long time1=clock();
int b[K*K];
for(int i=0;i<=K*K-1;i++)
b[i]=i+1;
//int num=0;
//do
//{
for(int i=0;i<=K*K-1;i++)
table[0][i]=i+1;
srand((unsigned int)time(NULL));
shuffle(table[0]);
for (int x=1;x<=K*K-1;x++) //这是核心 这两个for循环中的代码是实践调试改出来的,调试图片下面会附上
{
for (int y=0;y<=K*K-1;y++)
{
int i;
shuffle(b);
for( i=0;i<=K*K-1;i++)
{
if(test(x,y,b[i]))
{ table[x][y]=b[i]; break;}
}
if(i==K*K && y>0)
{
for(int m=0;m<=y-1;m++)
table[x][m]=0;
y=-1;
if(x>=2)
{
for(int i=0;i<=K*K-1;i++)
table[x-1][i]=0;
x-=2;
break;
}
}
else if(i==K*K && y==0)
{
for(int i=0;i<=K*K-1;i++)
table[x-1][i]=0;
x-=2;
break;
}
}
}
/*for(int i=0;i<=8;i++)
for(int j=0;j<=8;j++)
table[i][j]=0;*/
//num++;
//}while(num<1000);
for(int x=0;x<=K*K-1;x++)
{
for(int y = 0; y <=K*K-1; y++)
cout << table[x][y] << " ";
cout << endl;
}
time1=clock()-time1;
cout<<"use time "<<time1/1000<<"s"<<time1%1000<<"ms"<<endl;
system("pause");
}
//这个算法生成的的是一系列本质一样的终盘,其实只生成一个,
// 代码后面举两个生成的终盘
#include <stdio.h>
#include<cstdlib>
#include<time.h>
//using namespace std;
int Initial(int i, int j, int start);
int b[9]={1,2,3,4,5,6,7,8,9};
int data[9][9];
int line[9][9], column[9][9], block[9][9],data1[9][9];
void shuffle(int arr[])
{
int tmp, rd;
for(int i = 0; i <=8 ; i++)
{
rd = rand() % 9;
tmp = arr[rd];
arr[rd] = arr[i];
arr[i] = tmp;
}
}
int main()
{
int i, j;
long time1;
/* for (i = 0; i < 9; i++)
for (j = 0; j< 9; j++)
{
data[i][j] = 0; //数独阵线初始化为零
line[i][j] = 0; //行标记数组初始化
column[i][j] = 0; //列标记数组初始化
block[i][j] = 0; //块标记数组初始化
}*/
time1=clock();
srand(time(0));
shuffle(b);
Initial(0, 0, 8); //赋值函数
printf("%ums\n",clock()-time1);
for (i = 0; i < 9; i++) //打印数独阵
{
for (j = 0; j < 9; j++)
printf("%i ", data[i][j]);
printf("\n");
}
system("pause");
return 0;
}
int Initial(int i, int j, int start)
{
int k;
for (k = start;k>=0;k--) //从1至9依次试验
{
if (!line[i][b[k]-1] && !column[j][b[k]-1] && !block[i/3*3+j/3][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/3*3+j/3][b[k]-1] = 1;
if (i == 8 && j == 8) //初始化完毕退出
return 1;
if (j == 8) //定位下一位置
{
j = 0;
i++;
}
else
j++;
Initial(i, j, 8); //初始化下一位置
return 1;
}
if (k == 0) //1至9均无合适值,回溯
{
do
{
if (j == 0) //定位前一位置
{
j = 8;
i--;
}
else
j--;
line[i][data[i][j]-1] = 0;
column[j][data[i][j]-1] = 0;
block[i/3*3+j/3][data[i][j]-1] = 0;
}while (data[i][j] == b[0]);
//回溯到一可以继续的位置,从这一位置开始递归赋值
Initial(i, j, data1[i][j] -1);
return 1; //递归结束返回后立即退出
}
}
// return 1;
}
下面是另一种生成器,时间复杂度不如上面两种算法。
#include <iostream>
#include <cstdlib>
#include <ctime>
#include<time.h>
#include<cstdlib>
#define K 3
using namespace std;
int table[K*K][K*K];
void shuffle(int arr[],int m,int n)//小标为m--小标为n打乱顺序
{
int tmp, rd;
for(int i =m ; i <=n; i++)
{
rd = m+rand() % (n-m+1);
tmp = arr[rd];
arr[rd] = arr[i];
arr[i] = tmp;
}
}
bool test(int x, int y, int v)
{
int _x = x / K * K;
int _y = y / K * K;
//测试3 * 3矩阵内是否有重复的数
for(int i = _x; i <=x-1; i++)
for(int j = _y; j <= _y + K-1; j++)
if(table[i][j] == v) return false;
//测试横向、纵向是否有重复的数
for(int j = 0; j <=y-1; j++)
if(table[x][j] == v ) return false;
for(int i=0;i<=x-1;i++)
if(table[i][y]==v) return (false);
return true;
}
int check(int y,int x,int *mark) //求probable[y][x]
{
int i,j,is,js,count=0;
for(i=1;i<=K*K;++i)
mark[i]=0;
for(i=0;i<K*K;++i)
mark[table[y][i]]=1;
for(i=0;i<K*K;++i)
mark[table[i][x]]=1;
is=y/K*K;
js=x/K*K;
for(i=0;i<K;++i)
{
for(j=0;j<K;++j)
mark[table[is+i][js+j]]=1;
}
for(i=1;i<=K*K;++i)
if(mark[i]==0)
{ count++; mark[i]=i;}
else mark[i]=0;
shuffle(mark,1,K*K);
return count;
}
int main()
{
long time1=clock();
int b[K*K+1];
for(int i=0;i<=K*K-1;i++)
table[0][i]=i+1;
srand((unsigned int)time(NULL));
shuffle(table[0],0,K*K-1);
for (int x=1;x<=K*K-1;x++)
{
for (int y=0;y<=K*K-1;y++)
{
int i;
check(x,y,b);
for( i=1;i<=K*K;i++)
{
if(b[i]!=0)
{ table[x][y]=b[i]; break;}
}
if(i==K*K+1 && y>0)
{
for(int m=0;m<=y-1;m++)
table[x][m]=0;
y=-1;
if(x>=2)
{
for(int i=0;i<=K*K-1;i++)
table[x-1][i]=0;
x-=2;
break;
}
}
else if(i==K*K+1 && y==0)
{
for(int i=0;i<=K*K-1;i++)
table[x-1][i]=0;
x-=2;
break;
}
}
}
for(int x=0;x<=K*K-1;x++)
{
for(int y = 0; y <=K*K-1; y++)
cout << table[x][y] << " ";
cout << endl;
}
time1=clock()-time1;
cout<<"use time "<<time1/1000<<"s"<<time1%1000<<"ms"<<endl;
system("pause");
}
下面也是一种思路,不过耗时太长
#include <iostream>
#include <stdlib.h>
#include <time.h>
#include <conio.h>
#include<time.h>
#include<cstdlib>
using namespace std;
int sudoku[9][9],avail[9]={1,2,3,4,5,6,7,8,9};//定义数独数组和可选数字数组
void remove(int t[],int);//声明移除前置函数
void restore(void);//声明重置函数
void print(void);//声明打印数独函数
void init(void);//声明初始化函数
int search(int t[],int);//声明搜索下标函数
int en=9;//可选avail下标
void init() //初始化
{
int x,y;
srand(time(NULL));
for (y=0;y<=8;y++)
{
for (x=0;x<=8;x++)
{
sudoku[y][x]=0;
}
}//初始化数组
}
void remove(int t[],int n) //n为下标,移除排除下标,项前移
{
int i;
for (i=n;i<=7;i++)
{
t[i]=t[i+1];
}
en--;//可选数字在原有基础上减
}
int search(int t[],int n) //n为搜索的数字,返回下标,如果没有则返回-1
{
int i;
for (i=0;i<=en-1;i++)
if (t[i]==n)
return i;
return -1;
}
void restore() //初始化en,avail
{
int i;
en=9;
for (i=0;i<=8;i++)
avail[i]=i+1;
}
void print(void)
{
int i,j;
for (i=0;i<=8;i++)
{
for (j=0;j<=8;j++)
{
cout << sudoku[i][j] << " ";
}
cout << endl;
}
}
int main()
{
int x=0,y=0;
int kill;//已存在的数的小标
long time;
time=clock();
init();
cout << "正在生成一个数独..." << endl;
//restore();
for (y=0;y<=8;y++)
{
for (x=0;x<=8;x++)
{
int i,j;
for (i=0;i<=x;i++)//排除横行
{
kill=search(avail,sudoku[y][i]);
if (kill!=-1)
remove(avail,kill);
}
for (i=0;i<=y;i++)//排除纵行
{
kill=search(avail,sudoku[i][x]);
if (kill!=-1)
remove(avail,kill);
}
for (i=0;i<=2;i++) //排除九宫
{
for (j=0;j<=2;j++)
{
kill=search(avail,sudoku[(y/3)*3+i][(x/3)*3+j]);
if (kill!=-1)
remove(avail,kill);
}
}
if (en==0 && y>0) //排除无解
{
y-=2;
break;
}
else if (en==0 && y==0)
{
init();
y=-1;
break;
}
sudoku[y][x]=avail[rand()%en];
restore();
}
restore();
}
print();//打印数独
time=clock()-time;
cout<<"时间"<<time/1000<<"秒"<<time%1000<<"毫秒"<<endl;
system("pause");
}