数独终盘生成器(调试成果)

欢迎吹毛求疵   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");
}

 

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值