以下作成したプログラムの全文です。生成方法の種類により、一部書き換える必要があります。また、html出力部は坂本教授よりご提供頂きました。ありがとうございます。
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
#define N 9
#define B 3 //square root of N
#define swap(a,b) a^=b^=a^=b
#define R 1000 //反復回数
//#define DEBUG
void header(std::ostream& os){
os <<
"<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\">"
"<html lang=\"ja\">"
"<head>"
"<meta http-equiv=\"content-type\" content=\"text/html; charset=Shift_JIS\">"
"<title>数独</title>"
"<style>"
"td td{width: 3em; height:3em;text-align: center}"
"</style>"
"</head>"
"<body>"
<< std::endl;
}
void footer(std::ostream& os){
os <<
"</body>"
"</html>"
<< std::endl;
}
void inner(std::ostream&os, int top, const int * x){
os << "<table border=\"1\">" << std::endl;
for(int i=0; i<3; ++i){
os << "<tr>" << std::endl;
for(int j=0; j<3; ++j){
os << "<td>";
int value=x[top+i*9+j];
#ifndef DEBUG
if(value>0 ){
#endif
os<< value;
#ifndef DEBUG
}
#endif
os <<"</td>" << std::endl;
}
os << "</tr>" << std::endl;
}
os << "</table>" << std::endl;
}
std::ostream& operator<<(std::ostream& os, const int* x){
header(os);
os << "<table border=\"1\">" << std::endl;
for(int i=0; i<3; ++i){
os << "<tr>" << std::endl;
for(int j=0; j<3; ++j){
os << "<td>" ;
inner(os,i*27+j*3,x);
os << "</td>" << std::endl;
}
os << "</tr>" << std::endl;
}
os << "</table>" << std::endl;
footer(os);
return os;
}
void printResult(int board[]){//結果出力
int i,n=0;
for (i=0; i<N*N; ++i) {
if (N>9 && board[i]<10) printf(" ");//2桁整列用
printf("%d ", board[i]);
if (i%N==N-1) printf("\n");
}
printf("\n");
return;
}
int canBePlaced(int board[], int pos, int x)//check関数で仮に入れられた値が、縦・横・その値の所属の3×3マス(太枠)にあれば0を返す(なければ1を返す)
{
int row=pos/N;//row=行
int col=pos%N;//col=列
int i, j, topLeft;
for (i=0; i<N; ++i) {
if (board[row*N+i]==x) return 0;
if (board[col+i*N]==x) return 0;
}
topLeft=N*(row/B)*B+(col/B)*B;
for (i=0; i<B; ++i) {
for (j=0; j<B; ++j) {
if (board[topLeft+i*N+j]==x) return 0;
}
}
return 1;
}
int count0(int board[]){//配列内0の数を数える
int c=0;
for (int i=0; i<N*N; i++) {
if(board[i]==0)c++;
}
return c;
}
void cloneBoard(int boardOriginal[],int boardCopy[]){//前の配列を後ろのにコピペ
for (int i=0; i<N*N; i++) {
boardCopy[i]=boardOriginal[i];
}
}
void rand9(int randamboard[], int n){//1〜9の値をランダムに並び替える
srand((unsigned)time(NULL)+n);
for (int x=0; x<N; x++)randamboard[x]=x+1;
// numbersをランダムに並び替える
for(int i=0; i<N; i++){
int j =rand()%N;
if (i!=j)swap(randamboard[i], randamboard[j]);
}
return;
}
void rand81(int randBoard[],int n){//0〜80の値をランダムに並び替える
srand((unsigned)time(NULL)+n);
for (int x=0; x<N*N; x++)randBoard[x]=x;
// numbersをランダムに並び替える
for(int i=0; i<N*N; i++){
int j =rand()%N*N;
if (i!=j)swap(randBoard[i], randBoard[j]);
}
return;
}
void check(int board[], int pos, int n)//完成形を作成
{
int i, x, newPos, j=0;
//Solution is found.
if (pos==N*N) throw j;//メイン関数へ戻る
//Find a blank.
for (newPos=pos; newPos<N*N; ++newPos) {
if (board[newPos]==0) break;
}
//Check recursively.
for (x=0; x<N; ++x) {
int randBoard9[N];
rand9(randBoard9, n);//randBoard9=1〜9の値がランダムに入った配列。nはsrandのシード値を変えるのに使用。
int y=randBoard9[x];
if (canBePlaced(board, newPos, y)) {//if (boardのnewPosにrand9(x)が入れられるなら)
board[newPos]=y;
check(board, newPos+1,n+1);
board[newPos]=0;//backtracking
}
}
return;
}
void maker1(int board[], int n){//問題作成1 ランダム
int randBoard81[N*N];
rand81(randBoard81, n);
for (int x=0; x<N*N; x++){
int c=0;
int tmp=board[randBoard81[x]];
board[randBoard81[x]]=0;
for (int i=1; i<=N; i++){
if (canBePlaced(board, randBoard81[x], i))c++;
}
if(c!=1)board[randBoard81[x]]=tmp;
}
return;
}
void maker2(int board[], int n){//問題作成 順番指定
int cntBoard[]={
46,47,48,10,11,12,55,56,57,
49,50,51,13,14,15,58,59,60,
52,53,54,16,17,18,61,62,63,
19,20,21, 1, 2, 3,28,29,30,
22,23,24, 4, 5, 6,31,32,33,
25,26,27, 7, 8, 9,34,35,36,
64,65,66,37,38,39,73,74,75,
67,68,69,40,41,42,76,77,78,
70,71,72,43,44,45,79,80,81};
for (int x=0; x<N*N; x++){
int c=0;
int tmp=board[cntBoard[x]-1];
board[cntBoard[x]-1]=0;
for (int i=1; i<=N; i++){
if (canBePlaced(board, cntBoard[x]-1, i))c++;
}
if(c!=1)board[cntBoard[x]-1]=tmp;
}
return;
}
int main(){
clock_t start, end;
start = clock();
int board[N*N],boardDef[N*N],ave[5]={0,0,0,0,0};
int boardMax1[N*N],boardMax2[N*N];
int c=0, max1=0,max2=0, tmp;
for (int j=0; j<R; j++) {//反復回数
c++;//ループ毎のランダムシード変更用
for (int i=0; i<N*N; i++) {//配列内の要素を全て0で初期化
board[i]=0;
}
try {check(board, 0, c);}
catch (int b){/*printResult(board);*/}
cloneBoard(board,boardDef);
//printf( "パターン1\n\n");
maker1(board, 0);
//printResult(board);
tmp=count0(board);
//printf( "0の個数:%d[個]\n", tmp);
ave[0]+=tmp;
if(tmp>max1){//最大値測定用
cloneBoard(board,boardMax1);
max1=tmp;
}
cloneBoard(boardDef,board);
/*
//printf( "パターン2\n\n");
maker2(board, 0);
//printResult(board);
tmp=count0(board);
//printf( "0の個数:%d[個]\n", tmp);
ave[4]+=tmp;
if(tmp>max2){//最大値測定用
cloneBoard(board,boardMax2);
max2=tmp;
}*/
}
/*printf( "------------------------------\n");
printf( "パターン1\n平均:%d[個]\n", ave[0]/R);
printf( "最大:%d[個]\n", max1);
printResult(boardMax1);
printf( "パターン2\n平均:%d[個]\n", ave[1]/R);
printf( "最大:%d[個]\n", max2);
printResult(boardMax2);*/
end = clock();
printf( "処理時間:%d[ms]\n", end - start );
std::cout << boardMax1;
return 0;
}