测试 离散数学(隐形唯一数)回溯(cpu_nc)

QQ及邮箱:1 4 2 3 1 7 3 7 8 3 @qq.com 欢迎吹毛求疵。代码混乱黏贴到vc2010就很工整。

本代码摘自  数独游戏的解题算法——刘晓宝     《电脑编程技巧与维护》

//shuduf()函数的回溯部分可以用dfs,但用dfs反而更慢,这一问题在构造终盘有类似的荒谬的结论,在华东师大那篇文章中我也把搜索过程改为dfs但同样变慢了,本来想提速结果事与愿违,无法解释。

//神舟测试耗时约19.03h
#include<iostream>
#include<cstdlib>
#include<fstream>
#include<time.h>
#define N 9
using namespace std;

#define BLANKS   55
#define FAIL     20
int table[9][9],table_for_solve[9][9],solves=0;


struct shudu
{   int ok;  int bit;};
int op=1;

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);
void dfs();
int check(int y,int x,int *mark) ; //求probable[y][x]  并且mark[]中为0的元素说明可以试探
int solve22();
bool create_game(int blanks);
void create_gameover();
void print_all(int); 
void copy(int a[9][9],int b[9][9]);


int num2bit(int);
int bit2num(int);
int bits(int);
int has_bit(int,int);
int isrow(int,int);
int iscol(int,int);
int shuduf(struct shudu sd_array[N][N],int sd_nine[3][N]);
bool test(struct shudu sd[N][N]);

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 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_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<=9;++i)
    if(mark[i]==0)
       {
          table_for_solve[im][jm]=i;
          dfs();
       }
 table_for_solve[im][jm]=0;
}
int solve22()
{
 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_for_solve[y][i]]=1;
 for(i=0;i<9;++i)
  mark[table_for_solve[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_for_solve[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,col,tmp;
 for( i=1;i<=blanks;i++)
 {
  int num=0;
  do
  {
   do
   {
    k=rand()%81;
    row=k/9;
    col=k-9*row;
    tmp=table[row][col];
   }while(tmp==0);
   table[row][col]=0;
   copy(table_for_solve,table);
   num++;
   if(num==FAIL)   return(false);
  }while((solve22()==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;
    shuffle(table[0], 9);
                                                        //从第二行开始添入数字
    while(!put_line(1))   ;
}
void print_all(int k)

   for(int i=1;i<=9;i++)
     {
     if(i%3==1)  cout<<endl;
  for(int j=1;j<=9;j++)
     {
      if(j%3==1) cout<<"  ";
   cout<<table[i-1][j-1];
     }   
    cout<<endl;
     }
   cout<<endl<<endl;
}
void copy(int a[9][9],int b[9][9])
{
 for(int i=0;i<=8;i++)
  for(int j=0;j<=8;j++)
   a[i][j]=b[i][j];
}


int num2bit(int num)
{
 if(num<1) return(0);
 return(1<<(num-1));
}
int bit2num(int bit)
{
 int i,sum=0;
 for(i=1;i<=N;i++)
  if(has_bit(bit,num2bit(i)))    sum=sum*10+i;
 return(sum);
}
int bits(int bit)
{
 int i,sum=0;
 for(i=1;i<=N;i++)
  if(has_bit(bit,num2bit(i)))  sum++;
 return(sum);
}
int has_bit(int num,int bit)
{
 return(num & bit);
}
int isrow(int i,int j)
{
 return(i/3*3+j/3);
}
int iscol(int i,int j)
{
 return(i%3*3+j%3);
}
int shuduf(struct shudu sd_array[N][N],int sd_nine[3][N])
{
 int i,j,k,r,c,n,kok,temp_bit;
 struct shudu shudu_array[N][N];
 int shudu_nine[3][N];
 memcpy(shudu_array,sd_array,sizeof(struct shudu)*N*N);
 memcpy(shudu_nine,sd_nine,sizeof(int)*3*N);
 kok=1;
 while(kok==1)
 {
  kok=0;
  for(i=0;i<N;i++)
  {
   for(j=0;j<N;j++)
   {
    if(shudu_array[i][j].ok==0)
    {
     shudu_array[i][j].bit=(shudu_nine[0][i] | shudu_nine[1][j] | shudu_nine[2][isrow(i,j)])^(num2bit(N+1)-1);
     if(shudu_array[i][j].bit==0)   return(-1);//{ printf("\n第%d行,第%d列,为0,有误!\n",i+1,j+1);  return(-1);}
     if(bits(shudu_array[i][j].bit)==1)
     {
                       shudu_array[i][j].ok=1;  kok=1;
        shudu_nine[0][i]|=shudu_array[i][j].bit;
        shudu_nine[1][j]|=shudu_array[i][j].bit;
        shudu_nine[2][isrow(i,j)]|=shudu_array[i][j].bit;
     }
    }
    //printf("%9d|",bit2num(shudu_array[i][j].bit));
   }
   //printf("\n");
  }
  for(i=0;i<N;i++)
   for(j=0;j<N;j++)
   {
    r=c=n=0;
    for(k=0;k<N;k++)
     if(k!=j)
     {
      r|=shudu_array[i][k].bit;
      c|=shudu_array[k][i].bit;
      n|=shudu_array[isrow(i,j)][iscol(i,j)].bit;
     }
                r=shudu_array[i][j].bit & (r^shudu_array[i][j].bit);
    c=shudu_array[j][i].bit & (c^shudu_array[j][i].bit);
    n=shudu_array[isrow(i,j)][iscol(i,j)].bit & (n^shudu_array[isrow(i,j)][iscol(i,j)].bit);
    if(bits(r)==1 && shudu_array[i][j].ok==0)
    {
     if(has_bit(shudu_nine[0][i],r) || has_bit(shudu_nine[1][j],r) || has_bit(shudu_nine[2][isrow(i,j)],r) )
      return(-1);
     shudu_array[i][j].bit=r;
     shudu_array[i][j].ok=1;  kok=1;
     shudu_nine[0][i]|=shudu_array[i][j].bit;
     shudu_nine[1][j]|=shudu_array[i][j].bit;
     shudu_nine[2][isrow(i,j)]|=shudu_array[i][j].bit;
    }
    if(bits(c)==1 && shudu_array[j][i].ok==0)
    {
     if(has_bit(shudu_nine[0][j],c) || has_bit(shudu_nine[1][i],c) || has_bit(shudu_nine[2][isrow(j,i)],c) )
      return(-1);
     shudu_array[j][i].bit=c;
     shudu_array[j][i].ok=1;  kok=1;
     shudu_nine[0][j]|=shudu_array[j][i].bit;
     shudu_nine[1][i]|=shudu_array[j][i].bit;
     shudu_nine[2][isrow(j,i)]|=shudu_array[j][i].bit;
    }
    if(bits(n)==1 && shudu_array[isrow(i,j)][iscol(i,j)].ok==0)
    {
     if(has_bit(shudu_nine[0][isrow(i,j)],n) || has_bit(shudu_nine[1][iscol(i,j)],n) || has_bit(shudu_nine[2][i],n) )
      return(-1);
     shudu_array[isrow(i,j)][iscol(i,j)].bit=n;
     shudu_array[isrow(i,j)][iscol(i,j)].ok=1;  kok=1;
     shudu_nine[0][isrow(i,j)]|=shudu_array[isrow(i,j)][iscol(i,j)].bit;
     shudu_nine[1][iscol(i,j)]|=shudu_array[isrow(i,j)][iscol(i,j)].bit;
     shudu_nine[2][i]|=shudu_array[isrow(i,j)][iscol(i,j)].bit;
    }
   }
   //printf("=======================\n");
 }//while
 for(i=0;i<N;i++)  //检查题目是否得到解
  if(shudu_nine[0][i]==(num2bit(N+1)-1) && shudu_nine[1][i]==(num2bit(N+1)-1) && shudu_nine[2][i]==(num2bit(N+1)-1))   kok++;
 if(kok==N && test(shudu_array))     return(1);
 for(i=0;i<N;i++)
  for(j=0;j<N;j++)
   if(shudu_array[i][j].ok==0)
   {
    for(k=1;k<=N;k++)
     if(has_bit(shudu_array[i][j].bit,num2bit(k)))
     {
      temp_bit=shudu_array[i][j].bit;
      shudu_nine[0][i]|=num2bit(k);
      shudu_nine[1][j]|=num2bit(k);
      shudu_nine[2][isrow(i,j)]|=num2bit(k);
      shudu_array[i][j].ok=1;
      shudu_array[i][j].bit=num2bit(k);
      //printf("=======================\n");
      //printf("尝试:第%d行,第%d列,%d中的%d\n",i+1,j+1,bit2num(temp_bit),k);
      if(shuduf(shudu_array,shudu_nine)==1)    return(1);
      shudu_array[i][j].bit=temp_bit & (num2bit(k)^(num2bit(N+1)-1));
      shudu_array[i][j].ok=0;
      shudu_nine[0][i] &=(num2bit(k)^(num2bit(N+1)-1));
      shudu_nine[1][j] &=(num2bit(k)^(num2bit(N+1)-1));
      shudu_nine[2][isrow(i,j)] &=(num2bit(k)^(num2bit(N+1)-1));
     }
                if(shudu_array[i][j].bit==0)   return(-2);  //无解
   }
     return(1);
}//shuduf
bool test(struct shudu sd[N][N])
{
 int i,j;
 for(i=0;i<N;i++)
  for(j=0;j<N;j++)
   if(sd[i][j].ok!=1 ||  bits(sd[i][j].bit)!=1)  return(false);
 return(true);
}

int main()
{
   int i,j,rc;
   struct shudu shudu_array[N][N];
   int shudu_nine[3][N];
   long start,finish;
   start=clock();
   freopen("d:\\c++\\数独12\\question\\question475.txt","w",stdout);
   srand(time(0));
   for(op=1;op<=1000000;op++)
   {
 create_gameover();
 while(!create_game(BLANKS))
  create_gameover();
   memset(shudu_nine,0,sizeof(int)*3*N);
   for(i=0;i<N;i++)
    for(j=0;j<N;j++)
    {
     if(table[i][j]>0)
     {
      shudu_array[i][j].bit=num2bit(table[i][j]);
      shudu_array[i][j].ok=1;
     }
     else
     {
      shudu_array[i][j].bit=0;
      shudu_array[i][j].ok=0;
     }
     if(has_bit(shudu_nine[0][i],shudu_array[i][j].bit) || has_bit(shudu_nine[1][j],shudu_array[i][j].bit) || has_bit(shudu_nine[2][isrow(i,j)],shudu_array[i][j].bit) )
     {  printf("输入有误\n");  return(-1); }
     shudu_nine[0][i]|=shudu_array[i][j].bit;
     shudu_nine[1][j]|=shudu_array[i][j].bit;
     shudu_nine[2][isrow(i,j)]|=shudu_array[i][j].bit;
    }
   rc=shuduf(shudu_array,shudu_nine);
   if(rc==1)  ;
   else   { cout<<"测试第"<<op<<"个题目失败"<<endl;  print_all(1);}
   }
   finish=clock();
   cout<<finish-start<<"毫秒"<<endl;
   fclose(stdout);
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值