【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

 

posted @ 2013-10-23 23:40  g_word  阅读(244)  评论(0编辑  收藏  举报