您的位置:首页 > 其它

noip 2009 靶形数独

2017-03-04 15:06 423 查看
题目描述 Description

  小城和小华都是热爱数学的好学生,最近,他们不约而同地迷上了数独游戏,好胜的他
们想用数独来一比高低。但普通的数独对他们来说都过于简单了,于是他们向Z 博士请教,
Z 博士拿出了他最近发明的“靶形数独”,作为这两个孩子比试的题目。
靶形数独的方格同普通数独一样,在 9 格宽×9 格高的大九宫格中有9 个3 格宽×3 格
高的小九宫格(用粗黑色线隔开的)。在这个大九宫格中,有一些数字是已知的,根据这些

  数字,利用逻辑推理,在其他的空格上填入1 到9 的数字。每个数字在每个小九宫格内不能
重复出现,每个数字在每行、每列也不能重复出现。但靶形数独有一点和普通数独不同,即
每一个方格都有一个分值,而且如同一个靶子一样,离中心越近则分值越高。

  上图具体的分值分布是:最里面一格(黄色区域)为 10 分,黄色区域外面的一圈(红
色区域)每个格子为9 分,再外面一圈(蓝色区域)每个格子为8 分,蓝色区域外面一圈(棕
色区域)每个格子为7 分,最外面一圈(白色区域)每个格子为6 分,如上图所示。比赛的
要求是:每个人必须完成一个给定的数独(每个给定数独可能有不同的填法),而且要争取
更高的总分数。而这个总分数即每个方格上的分值和完成这个数独时填在相应格上的数字
的乘积的总和。如图,在以下的这个已经填完数字的靶形数独游戏中,总分数为2829。游
戏规定,将以总分数的高低决出胜负。

由于求胜心切,小城找到了善于编程的你,让你帮他求出,对于给定的靶形数独,能
够得到的最高分数。

#include<iostream>
#include<sstream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#include<cctype>
#include<cmath>
#include<algorithm>
#include<stack>
#include<queue>
#include<set>
#include<map>
#include<vector>
using namespace std;
typedef bool boolean;
#define smin(a, b)    (a) = min((a), (b))
#define smax(a, b)    (a) = max((a), (b))
template<typename T>
inline void readInteger(T& u){
char x;
int aFlag = 1;
while(!isdigit((x = getchar())) && x != '-');
if(x == '-'){
x = getchar();
aFlag = -1;
}
for(u = x - '0'; isdigit((x = getchar())); u = (u << 3) + (u << 1) + x - '0');
ungetc(x, stdin);
u *= aFlag;
}

typedef class Cell {
public:
int x, y;
int mask;

Cell(const int x = 0, const int y = 0, const int mask = 0):x(x), y(y), mask(mask) {           }

boolean operator < (Cell b) const {
if(x != b.x)    return x > b.x;
return y > b.y;
}
}Cell;

const int score[9][9] = {{6, 6, 6, 6, 6, 6, 6, 6, 6},
{6, 7, 7, 7, 7, 7, 7, 7, 6},
{6, 7, 8, 8, 8, 8, 8, 7, 6},
{6, 7, 8, 9, 9, 9, 8, 7, 6},
{6, 7, 8, 9, 10,9, 8, 7, 6},
{6, 7, 8, 9, 9, 9, 8, 7, 6},
{6, 7, 8, 8, 8, 8, 8, 7, 6},
{6, 7, 7, 7, 7, 7, 7, 7, 6},
{6, 6, 6, 6, 6, 6, 6, 6, 6}};
int result = -1;
short bmat[9][9];
int cells[9];
int lines[9];
int rows[9];
int sum;
Cell table[81];

void search(int s, int t){
if(t == 81){
smax(result, s);
return;
}
if(sum * 9 + s <= result)    return;
int x = table[t].x, y = table[t].y;
if(bmat[x][y] == 0){
int ce = (x / 3) * 3 + y / 3;
int seced = (rows[x] | lines[y]) | cells[ce];
for(int i = 8; i >= 0; i--){
if(!(seced & (1 << i))){
int mask = 1 << i;
rows[x] |= mask, lines[y] |= mask, cells[ce] |= mask, sum -= i + 1;
search(s + (i + 1) * score[x][y], t + 1);
rows[x] ^= mask, lines[y] ^= mask, cells[ce] ^= mask, sum += i + 1;
}
}
}else{
sum -= bmat[x][y];
search(s + bmat[x][y] * score[x][y], t + 1);
sum += bmat[x][y];
}
}

inline void init(){
for(int i = 0; i < 9; i++){
for(int j = 0; j < 9; j++){
readInteger(bmat[i][j]);
if(bmat[i][j] != 0){
int mask = (1 << (bmat[i][j] - 1));
rows[i] |= mask, lines[j] |= mask, cells[(i / 3) * 3 + j / 3] |= mask;
}
}
}
sum = 405;
}

const int full = (1 << 9) - 1;

inline void solve(){
for(int i = 0; i < 9; i++) {
for(int j = 0; j < 9; j++) {
if(bmat[i][j] != 0)
table[i * 9 + j] = Cell(i, j, full);
else table[i * 9 + j] = Cell(i, j, (rows[i] | lines[j]) | cells[(i / 3) * 3 + j / 3]);
}
}
sort(table, table + 81);
search(0, 0);
printf("%d", result);
}

int main(){
freopen("sudoku.in", "r", stdin);
freopen("sudoku.out", "w", stdout);
init();
solve();
return 0;
}


倒着搜索
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: