zoukankan      html  css  js  c++  java
  • 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
  • 相关阅读:
    洛谷 P1074 靶形数独 Label:search 不会
    TYVJ P3522 &&洛谷 P1135 奇怪的电梯 Label:bfs
    洛谷 P1160 队列安排 Label:链表 数据结构
    uestc 1073 秋实大哥与线段树 Label:线段树
    TYVJ P3407 佳佳的魔法照片 Label:语文很重要 语文很重要 语文很重要
    TYVJ P1103 多项式输出 Label:模拟 有点儿坑
    A+B Problem 详细解答 (转载)
    如何批量修改文件名
    c++ 在windows下获取时间和计算时间差的几种方法总结
    SQL Server 2008在Windows 10上不支持
  • 原文地址:https://www.cnblogs.com/wmq12138/p/10371395.html
Copyright © 2011-2022 走看看