测试 pure dlx(one form)

原链接:http://yzmduncan.iteye.com/blog/1151695

//测试花了17.58h
#include <iostream>  
#include<time.h>
#include<fstream>
using namespace std;
#define BLANKS   55
#define FAIL     20
int table[9][9],table_for_solve[9][9],solves=0;
fstream out_stream;
const int INF = 0x7fffffff;  
const int NN = 350;  
const int MM = 750;  
int n,m;    //列,行  
int cntc[NN];  
int L[NN*MM],R[NN*MM],U[NN*MM],D[NN*MM];  
int C[NN*MM];  
int head;  
int mx[MM][NN];  
int O[MM],idx,op;  
int ans[10][10];
int map[10][10]={0,0,0,0,0,0,0,0,0,0,
              0,8,0,0,0,0,0,0,0,0,
     0,0,0,3,6,0,0,0,0,0,
     0,0,7,0,0,9,0,2,0,0,
     0,0,5,0,0,0,7,0,0,0,
     0,0,0,0,0,4,5,7,0,0,
     0,0,0,0,1,0,0,0,3,0,
     0,0,0,1,0,0,0,0,6,8,
     0,0,0,8,5,0,0,0,1,0,
     0,0,9,0,0,0,0,4,0,0};

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 k);  //输出到文件
void copy(int a[9][9],int b[9][9]);

 

void remove(int);
void resume(int);
bool dfs();
bool build();
void print();
int test();
bool fun(int a[10]);

 


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)  out_stream<<endl;
  for(int j=1;j<=9;j++)
     {
      if(j%3==1) out_stream<<"  ";
   out_stream<<table[i-1][j-1];
     }   
    out_stream<<endl;
     }
   out_stream<<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];
}


 
//删除列及其相应的行  
void remove(int c)  
{  
    int i,j;  
    L[R[c]] = L[c];  
    R[L[c]] = R[c];  
    for(i = D[c]; i != c; i = D[i])  
    {  
        for(j = R[i]; j != i; j = R[j])  
        {  
            U[D[j]] = U[j];  
            D[U[j]] = D[j];  
            cntc[C[j]]--;  
        }  
    }  
}  
//恢复列及其相应的行  
void resume(int c)  
{  
    int i,j;  
    R[L[c]] = c;  
    L[R[c]] = c;  
    for(i = D[c]; i != c; i = D[i])  
    {  
        for(j = R[i]; j != i; j = R[j])  
        {  
            U[D[j]] = j;  
            D[U[j]] = j;  
            cntc[C[j]]++;  
        }  
    }  
}  
bool dfs()  
{  
    int i,j,c;  
    if(R[head] == head)  
        return true;  
    int min = INF;  
    for(i = R[head]; i != head; i = R[i])  
    {  
        if(cntc[i] < min)  
        {  
            min = cntc[i];  
            c = i;  
        }  
    }  
    remove(c);  
    for(i = D[c]; i != c; i = D[i])  
    {  
        //i是某点的序号,将该点所在行的行号保存  
        O[idx++] = (i-1)/n;  
        for(j = R[i]; j != i; j = R[j])  
            remove(C[j]);  
        if(dfs())  
            return true;  
        for(j = L[i]; j != i; j = L[j])  
            resume(C[j]);  
        idx--;  
    }  
    resume(c);  
    return false;  
}  
bool build()  
{  
    int i,j,now,pre,first;  
    idx = head = 0;  
    for(i = 0; i < n; i++)  
    {  
        R[i] = i+1;  
        L[i+1] = i;  
    }  
    R[n] = 0;  
    L[0] = n;  
    //列双向链表  
    for(j = 1; j <= n; j++)  
    {  
        pre = j;  
        cntc[j] = 0;  
        for(i = 1; i <= m; i++)  
        {  
            if(mx[i][j])  
            {  
                cntc[j]++;  
                now = i*n+j;  
                C[now] = j;  
                D[pre] = now;  
                U[now] = pre;  
                pre = now;  
            }  
        }  
        U[j] = pre;  
        D[pre] = j;  
        if(cntc[j] == 0)  
            return false;  
    }  
    //行双向链表  
    for(i = 1; i <= m; i++)  
    {  
        pre = first = -1;  
        for(j = 1; j <= n; j++)  
        {  
            if(mx[i][j])  
            {  
                now = i*n+j;  
                if(pre == -1)  
                    first = now;  
                else 
                {  
                    R[pre] = now;  
                    L[now] = pre;  
                }  
                pre = now;  
            }  
        }  
        if(first != -1)  
        {  
            R[pre] = first;  
            L[first] = pre;  
        }  
    }  
    return true;  
}  
void print()  
{  
    int i,j;  
        for(i = 1; i <= 9; i++)  
        {  
            if((i-1)%3==0) out_stream<<endl;
   for(j = 1; j <= 9; j++)  
                if((j-1)%3==0)  out_stream<<" "<<ans[i][j]<<" ";
    else out_stream<<ans[i][j]<<" ";//printf("%d",ans[i][j]);  
            out_stream<<endl;//printf("\n");  
        }  
}
int test()
  {
 int i,j;  
    int x,y,k;  
    for(i = 0; i < idx; i++)  
    {  
        int r = O[i];  
        k = r%9;  
        if(k==0) k = 9;  
        int num = (r - k)/9 + 1;  
        y = num%9;  
        if(y == 0) y = 9;  
        x = (num-y)/9 + 1;  
        ans[x][y] = k;  
    }  
 int sum=0,aray[10];
 for(int i=1;i<=9;i++)
  {
      sum=0;
   for(int j=1;j<=9;j++)
      { sum+=ans[i][j];  aray[j]=ans[i][j];}
   if(sum!=45) {cout<<"wrong"<<endl;   return 0;}
   if(!fun(aray))  return 0;
     }
 for( j=1;j<=9;j++)
  {
      sum=0;
   for(i=1;i<=9;i++)
         { sum+=ans[i][j];  aray[i]=ans[i][j];}
   if(sum!=45)  {cout<<"wrong"<<endl;   return 0;}
   if(!fun(aray))  return 0;
     }
 for(int k=1;k<=9;k++)
 {
  sum=0;
  int row=(k-1)/3*3+1,col=(k-1)%3*3+1,sub=1;
  for(i=row;i<=row+2;i++)
   for(j=col;j<=col+2;j++)
    { sum+=ans[i][j];  aray[sub++]=ans[i][j];}
        if(sum!=45)  {cout<<"wrong"<<endl;   return 0;}
  if(!fun(aray))  return 0;
 }
 return 1;
  }
bool  fun( int a[10])
{
 int i,j;
 for(i=1;i<=8;i++)
 {
  if(*(a+i)==0)  continue;
  for(j=i+1;j<=9;j++)
   if(*(a+i)==*(a+j)) return (false);
 }
 return (true);
}


int main()  
{  
    int i,j,k;  
 long time1,time2;
 char s[10][10];
 srand(time(0));
 time1=clock();
 out_stream.open("d:\\my documents\\visual studio 2010\\projects\\测试算法\\测试pure dlx(one form).txt");
 for( op=1;op<=1000000;op++)
 {
  create_gameover();
        while(!create_game(BLANKS))
   create_gameover();
  /*for(int i=1;i<=9;i++)
   for(int j=1;j<=9;j++)
    if(map[i][j])  s[i][j]=48+map[i][j];
    else   s[i][j]='?';*/
  for(int i=1;i<=9;i++)
   for(int j=1;j<=9;j++)
    if(table[i-1][j-1])  s[i][j]=48+table[i-1][j-1];
    else   s[i][j]='?';
        memset(mx,0,sizeof(mx));
        for(i = 1; i <= 9; i++)  
        {  
            for(j = 1; j <= 9; j++)  
             {  
                int t = (i-1)*9 + j;  
                if(s[i][j] == '?')  
                {  
                    for(k = 1; k <= 9; k++)  
                    {  
                        mx[9*(t-1)+k][t] = 1;               //81grid 每个小格只能放一个数字  
                        mx[9*(t-1)+k][81+(i-1)*9+k] = 1;    //9row 每行数字k只能出现一次  
                        mx[9*(t-1)+k][162+(j-1)*9+k] = 1;   //9col  每列数字k只能出现一次  
                        mx[9*(t-1)+k][243+((i-1)/3*3+(j+2)/3-1)*9+k] = 1;   //subgrid 每个3*3格子数字k只能出现一次  
                    }  
                }  
                else 
                {  
                    k = s[i][j] - '0';  
                    mx[9*(t-1)+k][t] = 1;               //81grid  
                    mx[9*(t-1)+k][81+(i-1)*9+k] = 1;    //9row  
                    mx[9*(t-1)+k][162+(j-1)*9+k] = 1;   //9col  
                    mx[9*(t-1)+k][243+((i-1)/3*3+(j+2)/3-1)*9+k] = 1;   //subgrid  
                }  
            }  
        }  
        n = 324;  
        m = 729;  
        build();
        dfs();
  if(test()) ;
  else  {   out_stream<<op<<endl; print_all(1); print();}
  idx=0;
 } 
 time2=clock();
 out_stream<<"用时"<<(time2-time1)/1000<<"s"<<(time2-time1)%1000<<"ms"<<endl;
 out_stream.close();
    return 0;  

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值