NOIp 2009:靶形数独
题目描述 Description 小城和小华都是热爱数学的好学生,最近,他们不约而同地迷上了数独游戏,好胜的他 们想用数独来一比高低。但普通的数独对他们来说都过于简单了,于是他们向Z 博士请教, Z 博士拿出了他最近发明的“靶形数独”,作为这两个孩子比试的题目。 靶形数独的方格同普通数独一样,在 9 格宽×9 格高的大九宫格中有9 个3 格宽×3 格 高的小九宫格(用粗黑色线隔开的)。在这个大九宫格中,有一些数字是已知的,根据这些 数字,利用逻辑推理,在其他的空格上填入1 到9 的数字。每个数字在每个小九宫格内不能 重复出现,每个数字在每行、每列也不能重复出现。但靶形数独有一点和普通数独不同,即 每一个方格都有一个分值,而且如同一个靶子一样,离中心越近则分值越高。 上图具体的分值分布是:最里面一格(黄色区域)为 10 分,黄色区域外面的一圈(红 色区域)每个格子为9 分,再外面一圈(蓝色区域)每个格子为8 分,蓝色区域外面一圈(棕 色区域)每个格子为7 分,最外面一圈(白色区域)每个格子为6 分,如上图所示。比赛的 要求是:每个人必须完成一个给定的数独(每个给定数独可能有不同的填法),而且要争取 更高的总分数。而这个总分数即每个方格上的分值和完成这个数独时填在相应格上的数字 的乘积的总和。如图,在以下的这个已经填完数字的靶形数独游戏中,总分数为2829。游 戏规定,将以总分数的高低决出胜负。 由于求胜心切,小城找到了善于编程的你,让你帮他求出,对于给定的靶形数独,能 够得到的最高分数。 输入描述 Input Description 一共 9 行。每行9 个整数(每个数都在0—9 的范围内),表示一个尚未填满的数独方 格,未填的空格用“0”表示。每两个数字之间用一个空格隔开。 输出描述 Output Description 输出可以得到的靶形数独的最高分数。如果这个数独无解,则输出整数-1。 样例输入 Sample Input 【输入输出样例 1】 7 0 0 9 0 0 0 0 1 1 0 0 0 0 5 9 0 0 0 0 0 2 0 0 0 8 0 0 0 5 0 2 0 0 0 3 0 0 0 0 0 0 6 4 8 4 1 3 0 0 0 0 0 0 0 0 7 0 0 2 0 9 0 2 0 1 0 6 0 8 0 4 0 8 0 5 0 4 0 1 2 【输入输出样例 2】 0 0 0 7 0 2 4 5 3 9 0 0 0 0 8 0 0 0 7 4 0 0 0 5 0 1 0 1 9 5 0 8 0 0 0 0 0 7 0 0 0 0 0 2 5 0 3 0 5 7 9 1 0 8 0 0 0 6 0 1 0 0 0 0 6 0 9 0 0 0 0 1 0 0 0 0 0 0 0 0 6 样例输出 Sample Output 【输入输出样例 1】 2829 【输入输出样例 1】 2852 数据范围及提示 Data Size & Hint 【数据范围】 40%的数据,数独中非0 数的个数不少于30。 80%的数据,数独中非0 数的个数不少于26。 100%的数据,数独中非0 数的个数不少于24。
芒果君:爆搜里我认为很经典的题目,为了达到时限我也重构+调试了若干个小时,就说说自己的思路。
刚开始肯定都是正搜(左上到右下),没想到数据问题,倒搜快了好多,那我就想,能不能将9*9划分成四个象限(5*5),再判断搜索的起始点,不过比之前更慢了OTZ
之后看了一下题解,发现自己一直局限在某个角,而没有全局的看整个棋盘,接着就是不断地重构调试……
最后到极限……这是codevs上最慢的一个点了--> 测试点#sudoku20.in 结果:<label>AC</label> 内存使用量: 256kB 时间使用量: 222ms
O_o ->每个空格子的信息——横纵坐标和初始有哪些数可选,红字部分是剪枝的要点,预处理,之后我们的每次填数肯定都要看这个大的格局。贪心的,每次我们找到出度(可选的数)最小的格子去搜,但这个出度不能为0,如果为0就说明不能填了对不对w 如果为1呢,一定去填这个格子,直接跳出。
其实借鉴了别人的思想,但如果每次都在9*9*9范围内找显然有许多不必要的操作,我的优化就在于把寻找的范围缩小到每个空格和初始能填的数,用结构体存,比如(1,1)一开始能填的数是(1,2,3),那我只要看这3个数而不用再把一到九找一遍,然后还有毫无卵用的位运算,就缩了一点空间……还有更无卵用的register和inline什么鬼2333333
1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #include<algorithm> 5 #include<cmath> 6 #define calg(x,y) ((x-1)/3)*3+(y-1)/3+1 7 using namespace std; 8 int cnt,ans=-1,now,vis[90],score[10][10][10],mp[10][10],MP[10][10],r[10],c[10],g[10],w[10][10]={{},{0,6,6,6,6,6,6,6,6,6},{0,6,7,7,7,7,7,7,7,6},{0,6,7,8,8,8,8,8,7,6},{0,6,7,8,9,9,9,8,7,6},{0,6,7,8,9,10,9,8,7,6},{0,6,7,8,9,9,9,8,7,6},{0,6,7,8,8,8,8,8,7,6},{0,6,7,7,7,7,7,7,7,6},{0,6,6,6,6,6,6,6,6,6}}; 9 struct Ge{ 10 int x,y,ccnt; 11 int list[10]; 12 }O_o[90]; 13 inline int read() 14 { 15 int ret=0; 16 char ch=getchar(); 17 while(ch<'0'||ch>'9') ch=getchar(); 18 while(ch>='0'&&ch<='9'){ 19 ret=ret*10+ch-'0'; 20 ch=getchar(); 21 } 22 return ret; 23 } 24 bool cmp(Ge X,Ge Y) 25 { 26 if(X.ccnt!=Y.ccnt) return X.ccnt<Y.ccnt; 27 if(X.x!=Y.x) return X.x<Y.x; 28 return X.y<Y.y; 29 } 30 inline bool fill(register int x,register int y,register int val) 31 { 32 if(r[x]&(1<<val)||c[y]&(1<<val)||g[calg(x,y)]&(1<<val)) return false; 33 r[x]|=1<<val,c[y]|=1<<val,g[calg(x,y)]|=1<<val; 34 now+=score[x][y][val]; 35 return true; 36 } 37 void dfs(register int f,register int sum) 38 { 39 if(sum>cnt){ 40 ans=max(now,ans); 41 return; 42 } 43 vis[f]=1; 44 register int x=O_o[f].x,y=O_o[f].y,flg=1; 45 for(register int j=1;j<=O_o[f].ccnt;++j){ 46 register int i=O_o[f].list[j],minx=10,zb=0; 47 if(fill(x,y,i)){ 48 flg=1; 49 for(int k=1;k<=cnt;++k){ 50 if(vis[k]) continue; 51 int cd=O_o[k].ccnt,xx=O_o[k].x,yy=O_o[k].y; 52 for(int l=1;l<=O_o[k].ccnt;++l){ 53 int nnum=O_o[k].list[l]; 54 if(r[xx]&(1<<nnum)||c[yy]&(1<<nnum)||g[calg(xx,yy)]&(1<<nnum)) cd--; 55 } 56 if(!cd){ 57 flg=0; 58 break; 59 }; 60 if(cd<minx){ 61 minx=cd; 62 zb=k; 63 } 64 if(cd==1) break; 65 } 66 if(flg) dfs(zb,sum+1); 67 r[x]^=1<<i,c[y]^=1<<i,g[calg(x,y)]^=1<<i; 68 now-=score[x][y][i]; 69 } 70 } 71 vis[f]=0; 72 } 73 int main() 74 { 75 //freopen("sudoku.in","r",stdin); 76 //freopen("sudoku.out","w",stdout); 77 for(int i=1;i<=9;++i) 78 for(int j=1;j<=9;++j) 79 for(int k=1;k<=9;++k) 80 score[i][j][k]=w[i][j]*k; 81 for(int i=9;i>0;--i) 82 for(int j=9;j>0;--j){ 83 mp[i][j]=read(); 84 fill(i,j,mp[i][j]); 85 } 86 for(int i=1;i<=9;++i) 87 for(int j=1;j<=9;++j){ 88 if(mp[i][j]) continue; 89 O_o[++cnt].x=i; 90 O_o[cnt].y=j; 91 for(int k=1;k<=9;++k){ 92 if(r[i]&(1<<k)||c[j]&(1<<k)||g[calg(i,j)]&(1<<k)) continue; 93 else O_o[cnt].list[++O_o[cnt].ccnt]=k; 94 } 95 } 96 sort(O_o+1,O_o+cnt+1,cmp); 97 dfs(1,1); 98 printf("%d",ans); 99 return 0; 100 }