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 }