【noip2009】靶形数独

题解:

又是搜索- - 加状态压缩剪枝

二进制记下每行 每列 每个九宫格用过的数是谁 枚举的时候可以O(1)判断冲突

还有个很重要的剪枝 把可能使用数字最少的格子先搜索

 

代码:

  1 #include <cstdio>

  2 #include <cstdlib>

  3 #include <algorithm>

  4 using std::sort;

  5 const int N=82,n=9,val[10][10]={{0,0,0,0,0,0,0,0,0,0},

  6                                 {0,6,6,6,6,6,6,6,6,6},

  7                                 {0,6,7,7,7,7,7,7,7,6},

  8                                 {0,6,7,8,8,8,8,8,7,6},

  9                                 {0,6,7,8,9,9,9,8,7,6},

 10                                 {0,6,7,8,9,10,9,8,7,6},

 11                                 {0,6,7,8,9,9,9,8,7,6},

 12                                 {0,6,7,8,8,8,8,8,7,6},

 13                                 {0,6,7,7,7,7,7,7,7,6},

 14                                 {0,6,6,6,6,6,6,6,6,6}};

 15 struct info{

 16     int x,y,z;

 17     info(const int a=0,const int b=0,const int c=0):

 18         x(a),y(b),z(c){}

 19 }im[10][10],v[N];

 20 int map[10][10],xx[10],yy[10],zz[10],ans,maxans,rem;

 21 inline bool cmp(info a,info b){ return a.z>b.z || (a.z==b.z && a.x<b.x) || (a.z==b.z && a.x==b.x && a.y<b.y); }

 22 void print(int t){

 23     printf("%d",t);

 24     exit(0);

 25 }

 26 void makeim(){

 27     for (int i=1;i<=n;i++)

 28     for (int j=1;j<=n;j++){

 29         im[i][j].x=i;

 30         im[i][j].y=j;

 31         if (i<=3){

 32             if (j<=3) im[i][j].z=1;

 33             else if (j<=6) im[i][j].z=2;

 34             else im[i][j].z=3;

 35         }else if (i<=6){

 36             if (j<=3) im[i][j].z=4;

 37             else if (j<=6) im[i][j].z=5;

 38             else im[i][j].z=6;

 39         }else{

 40             if (j<=3) im[i][j].z=7;

 41             else if (j<=6) im[i][j].z=8;

 42             else im[i][j].z=9;

 43         }

 44     }

 45 }

 46 void makexyz(){

 47     for (int i=1;i<=n;i++)

 48     for (int j=1;j<=n;j++)

 49     if (map[i][j]){

 50         if ((xx[im[i][j].x]>>(map[i][j]-1))&1) print(-1);

 51         if ((yy[im[i][j].y]>>(map[i][j]-1))&1) print(-1);

 52         if ((zz[im[i][j].z]>>(map[i][j]-1))&1) print(-1);

 53         xx[im[i][j].x]|=1<<(map[i][j]-1);

 54         yy[im[i][j].y]|=1<<(map[i][j]-1);

 55         zz[im[i][j].z]|=1<<(map[i][j]-1);

 56     }

 57 }

 58 void makev(){

 59     for (int i=1;i<=n;i++)

 60     for (int j=1;j<=n;j++) v[(i-1)*n+j]=info(i,j,val[i][j]);

 61     sort(v+1,v+82,cmp);

 62 }

 63 bool check(int x,int y,int z){

 64     --z;

 65     if ((xx[im[x][y].x]>>z)&1) return 0;

 66     if ((yy[im[x][y].y]>>z)&1) return 0;

 67     if ((zz[im[x][y].z]>>z)&1) return 0;

 68     return 1;

 69 }

 70 void add(int x,int y,int z,int bo){

 71     --z;

 72     xx[im[x][y].x]+=bo*(1<<z);

 73     yy[im[x][y].y]+=bo*(1<<z);

 74     zz[im[x][y].z]+=bo*(1<<z);

 75 }

 76 int getsave(int t){

 77     int res=0;

 78     for (;t;t>>=1) res+=t&1;

 79     return res;

 80 }

 81 void search(){

 82     if (ans+rem*9<=maxans) return;

 83     int x=0,y,z=0;

 84     for (int i=1;i<=n;i++)

 85     for (int j=1;j<=n;j++)

 86     if (!map[i][j]){

 87         int save=getsave(xx[im[i][j].x]|yy[im[i][j].y]|zz[im[i][j].z]);

 88         if (save==9) return;

 89         if (save>z) z=save,x=i,y=j;

 90     }

 91     if (!x){

 92         if (maxans<ans) maxans=ans;

 93         return;

 94     }

 95     for (int i=9;i;i--)

 96     if (check(x,y,i)){

 97         rem-=i;

 98         ans+=i*val[x][y];

 99         add(x,y,i,1);

100         map[x][y]=i;

101         search();

102         map[x][y]=0;

103         add(x,y,i,-1);

104         ans-=i*val[x][y];

105         rem+=i;

106     }

107 }

108 int main(){

109     rem=45*9;

110     for (int i=1;i<=n;i++)

111     for (int j=1;j<=n;j++){

112         scanf("%d",&map[i][j]);

113         rem-=map[i][j];

114         ans+=map[i][j]*val[i][j];

115     }

116     makeim();

117     makexyz();

118     makev();

119     search();

120     if (maxans) print(maxans);

121     puts("-1");

122 }
View Code

 

你可能感兴趣的:(IP)