欢迎吹毛求疵 QQ: 1423173783 邮箱:1423173783@qq.com
//代码弱点:挖洞只能挖少量洞 构造法只能给出一种终盘 想生成25*25题目 实时生成几乎没办法无奈出此下策
//程序思想: 先构造一种终盘(构造终盘的方法请参考我的上一篇有大量图片的博文) 然后挖洞 每挖一个洞调用解题代码解题如只有一个解继续挖,如有多解重新找别的格子挖直到挖了设定的BLANKS个格子
//如果在挖第n个格子时,选取了FAIL个格子挖,调用解题代码解出都要多解,说明前面挖的不合理(这个判断是不科学的,用耗时换取很少出现的不合理的情况),但这样做逻辑上万无一失,对建题库是有帮助的。
#include<iostream>
#include<time.h>
#include<cstdlib>
#include<fstream>
#define K 5
#define BLANKS 300
#define FAIL 20
using namespace std;
fstream out_stream;
int table[K*K+1][K*K+1],table_for_solve[K*K+1][K*K+1],solves=0;
void move_1pos(int a[K*K+1]);
void move_kpos(int a[K*K+1]);
void copy(int a[K*K+1],int b[K*K+1]);
void copy(int a[K*K+1][K*K+1],int b[K*K+1][K*K+1]);
void create_gameover();
void print_all();
void print_all(int k);//输出到屏幕
void dfs();
int solve();
int check(int y,int x,int *mark); //求probable[y][x]
bool create_game(int blanks);
void move_1pos(int a[K*K+1])
{
int tmp=a[1];
for(int i=2;i<=K*K;i++)
a[i-1]=a[i];
a[K*K]=tmp;
}
void move_kpos(int a[K*K+1])
{
int b[K+1];
for(int i=1;i<=K;i++)
b[i]=a[i];
for(int i=K+1;i<=K*K;i++)
a[i-K]=a[i];
for(int i=K*(K-1)+1;i<=K*K;i++)
a[i]=b[i-K*(K-1)];
}
void copy(int a[K*K+1],int b[K*K+1])
{
for(int i=1;i<=K*K;i++)
a[i]=b[i];
}
void copy(int a[K*K+1][K*K+1],int b[K*K+1][K*K+1])
{
for(int i=1;i<=K*K;i++)
for(int j=1;j<=K*K;j++)
a[i][j]=b[i][j];
}
void create_gameover()
{
static int num1[K*K+1],num2[K*K+1];
for(int i=1;i<=K*K;i++)
{ num1[i]=i; num2[i]=i;}
for(int i=1;i<=K;i++)
{
for(int j=1;j<=K;j++)
{
for(int k=1;k<=K*K;k++)
table[K*(i-1)+j][k]=num2[k];
move_kpos(num2);
}
move_1pos(num1);
copy(num2,num1);
}
}
void print_all()
{
//out_stream<<"print storage"<<endl;
for(int i=1;i<=K*K;i++)
{
for(int j=1;j<=K*K;j++)
{
out_stream<<table[i][j]<<" ";
if(j%K==0) out_stream<<" ";
}
out_stream<<endl;
if(i%K==0) out_stream<<endl;
}
out_stream<<endl<<endl;
}
void print_all(int k)//输出到屏幕
{
cout<<"print storage"<<endl;
for(int i=1;i<=K*K;i++)
{
for(int j=1;j<=K*K;j++)
{
cout<<table[i][j]<<" ";
if(j%K==0) cout<<" ";
}
cout<<endl;
if(i%K==0) cout<<endl;
}
cout<<endl<<endl;
}
void dfs()
{
int i,j,im=-1,jm,min=100;
int mark[K*K+1];
for(i=1;i<=K*K;++i)
for(j=1;j<=K*K;++j)
{
if(table_for_solve[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<=K*K;++i)
if(mark[i]==0)
{
table_for_solve[im][jm]=i;
dfs();
}
table_for_solve[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<=K*K;++i)
mark[i]=0;
for(i=1;i<=K*K;++i)
mark[table_for_solve[y][i]]=1;
for(i=1;i<=K*K;++i)
mark[table_for_solve[i][x]]=1;
is=(y-1)/K*K+1;
js=(x-1)/K*K+1;
for(i=0;i<K;++i)
for(j=0;j<K;++j)
mark[table_for_solve[is+i][js+j]]=1;
for(i=1;i<=K*K;++i)
if(mark[i]==0)
count++;
return count;
}
bool create_game(int blanks)
{
int i,k,row,col,tmp;
for( i=1;i<=blanks;i++)
{
int num=0;
do
{
do
{
k=rand()%(K*K*K*K)+1;
row=(k-1)/K+1;
col=k-K*K*(row-1);
tmp=table[row][col];
}while(tmp==0);
table[row][col]=0;
copy(table_for_solve,table);
num++;
if(num==FAIL) return(false);
}while((solve()==2)? table[row][col]=tmp : 0);
}
if(i=blanks+1) return (true);
}
int main()
{
create_gameover();
print_all(1);
while(!create_game(BLANKS)) ;
out_stream.open("d:\\c++\\数独12\\question\\5-5-4.txt");
print_all();
out_stream.close();
system("pause");
}