POJ3076 Sudoku

POJ3076 Sudoku

  • 本题为16*16宫格
  • 剪枝见代码
  1 #include <cstdio>
  2 #include <iostream>
  3 #include <algorithm>
  4 #include <cstring>
  5 using namespace std;
  6 const int N=20;
  7 
  8 #define res register int
  9 int map[N][N];
 10 unsigned short t[N][N];
 11 //table[i,j](二进制)表示(i,j)可以填的数,0可填,1不可填
 12 int filled(0);
 13 
 14 inline void my_fill(int x,int y,int a)//(x,y)填a
 15 {
 16     filled++;
 17     map[x][y]=a;
 18     t[x][y] |=1<<(a-1);
 19     for(res i=0 ; i<16 ; i++) 
 20         t[x][i] |=1<<(a-1),
 21         t[i][y] |=1<<(a-1);
 22     int r=x/4*4,c=y/4*4;//(r,c)表示(x,y)所在的16宫格的左上角的格子,(从(0,0)开始)
 23     for(res i=0 ; i<4 ; i++)
 24         for(res j=0 ; j<4 ; j++) t[r+i][j+c] |=1<<(a-1);
 25 }
 26 
 27 //判断x中0的个数是否只有1个 
 28 int count_zero(unsigned short x)
 29 {
 30     int p(-1);
 31     for(int i=0;x;i++)
 32     {
 33         if(x&1==0)
 34         {
 35             if(p!=-1) return -1;
 36             p=i;
 37         }
 38         x>>=1;
 39     }
 40     return p;
 41 }
 42 
 43 //第x行,数字k+1,返回>0表示唯一可填的k+1的位置,-1表示有多个可以填的位置或已经填过,-2不能填
 44 inline int col(int x,int k)
 45 {
 46     int p(-1);
 47     for(res y=0 ; y<16 ; y++)
 48     {
 49         if(map[x][y]==k+1) return -1;//已经填过
 50         if(map[x][y]>0) continue;
 51         if((t[x][y]&(1<<k))==0)
 52         {
 53             if(p!=-1) return -1;//多次出现
 54             p=y;
 55         }
 56     }
 57     if(p!=-1) return p;
 58     return -2;
 59 }
 60 
 61 //第y列,数字k
 62 inline int row(int y,int k)
 63 {
 64     int p=-1;
 65     for(res x=0 ; x<16 ; x++)
 66     {
 67         if(map[x][y]==k+1) return -1;
 68         if(map[x][y]>0) continue;
 69         if((t[x][y]&(1<<k))==0)
 70         {
 71             if(p!=-1) return -1;
 72             p=x;
 73         }
 74     }
 75     if(p!=-1) return p;
 76     return -2;
 77 }
 78 
 79 inline void grid(int r,int c,int k,int &x,int &y)
 80 //以(r,c)为左上角的16宫格,数字k+1,(x,y)为唯一可填坐标[
 81 {
 82     x=-2;
 83     for(res i=0 ; i<4 ; i++)
 84         for(res j=0 ; j<4 ; j++)
 85         {
 86             if(map[r+i][c+j]==k+1) {x=-1; return ;}
 87             if(map[r+i][c+j]>0) continue;
 88             if((t[r+i][c+j]&(1<<k))==0)
 89             {
 90                 if(x!=-2) {x=-1; return ;}
 91                 x=i,y=j;
 92             }
 93         }
 94 }
 95 
 96 inline int count_1(unsigned short x) {
 97     int tmp(0);
 98     while(x) {
 99         if(x&1) tmp++;
100         x>>=1;
101     }
102     return tmp;
103 }
104 
105 bool search()
106 {
107     if(filled==256) return true;
108     //先看是否有能确定的格子
109     for(res x=0 ; x<16 ; x++)
110         for(res y=0 ; y<16 ; y++)
111         {
112             if(map[x][y]>0) continue;
113             int k=count_zero(t[x][y]);
114             if(k!=-1) my_fill(x,y,k+1);
115         }
116     for(res x=0 ; x<16 ; x++)
117         for(res k=0 ; k<16 ; k++)
118         {
119             int y=col(x,k);
120             if(y==-2) return false;
121             if(y!=-1) my_fill(x,y,k+1);
122         }
123     for(res y=0 ; y<16 ; y++)
124         for(res k=0 ; k<16 ; k++)
125         {
126             int x=row(y,k);
127             if(x==-2) return false;
128             if(x!=-1) my_fill(x,y,k+1);
129         }
130     for(res r=0 ; r<16 ; r+=4)
131         for(res c=0 ; c<16 ; c+=4)
132             for(res k=0 ; k<16 ; k++)
133             {
134                 int x,y;
135                 grid(r,c,k,x,y);
136                 if(x==-2) return false;
137                 if(x!=-1) my_fill(r+x,c+y,k+1);
138             }
139     if(filled==256) return true;
140     int t_filled(filled);
141     int t_map[N][N]; 
142     unsigned short t_t[N][N];
143     for(res i=0 ; i<16 ; i++)
144         for(res j=0 ; j<16 ; j++)
145             t_map[i][j]=map[i][j],
146             t_t[i][j]=t[i][j];
147     //找可能情况最少的格子来枚举
148     int mx,my,mn=16;
149     for(res i=0 ; i<16 ; i++)
150         for(res j=0 ; j<16 ; j++)
151         {
152             if(map[i][j]>0) continue;
153             int r=16-count_1(t[i][j]);
154             //未确定的 
155             if(r<mn)
156             {
157                 mn=r; mx=i; my=j;
158             }
159         }
160     for(res k=0 ; k<16 ; k++)
161         if((t[mx][my]&1<<k)==0)
162         {
163             my_fill(mx,my,k+1);
164             if(search()) return true;
165             filled=t_filled;
166             for(res i=0 ; i<16 ; i++)
167                 for(res j=0 ; j<16 ; j++)
168                     map[i][j]=t_map[i][j],
169                     t[i][j]=t_t[i][j];
170         }
171         return false;
172 }
173 
174 char ar[N];
175 int main()
176 {
177     while(1)
178     {
179         filled=0;
180         memset(map,0,sizeof(map)); memset(t,0,sizeof(t));
181         for(int i=0 ; i<16 ; i++)
182         {
183             if(scanf("%s",ar)==EOF) return 0;
184             for(int j=0 ; j<16 ; j++)
185                 if(ar[j]!='-') my_fill(i,j,ar[j]-'A'+1);
186         }
187         search();
188         for(res i=0 ; i<16 ; i++)
189         {
190             for(res j=0 ; j<16 ; j++) printf("%c",map[i][j]+'A'-1);
191             puts("");
192         }
193         puts("");
194     }
195     return 0;
196 }
View Code

 

posted @ 2019-02-13 18:38  孑行  阅读(515)  评论(0编辑  收藏  举报