您的位置:首页 > 其它

NOIP 2009 靶形数独 解题报告

2011-08-10 16:24 519 查看
  就是用位运算,直接读出一行中应该放的位置和该放的数字,然后枚举。但不是随意的枚举,要从已经填的最多的那行开始搜,最后搜内容最空白的一行,至于为什么呢?想一想吧,一行中要填的空白多(就是已经填的很少),那每个个子里面可以装的数字就越多,相反,需要填写的很少,那么枚举的情况就少。就是说比如第i行只有一个数字要填,在这一列下面还有几行是空白的,那这一个是确定的,是已知的,只有这一种可能,那在枚举其余行这一列就少了一种可能性,懂了么?

  好了,这一个细节纠结了我很久,上代码了:

#include <stdio.h>
#include <stdlib.h>
#define con(i) (1 << (i))
#define getid(i, j) ((i) / 3 * 3 + (j) / 3)
#define getidorder(i, j) (3 * ((i) - (i) / 3 * 3) + (j) - (j) / 3 * 3)
int map[9][9];
int row[9];
int n_row[9], n_line[9];
int small[9];
int f[512];

int ans;
int sore[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}};

void getgrade(void)
{
int i, j;
int t = 0;
for(i = 0; i < 9; i++){
for(j = 0; j < 9; j++){
t += map[i][j] * sore[i][j];
}
}
if(ans < t){
ans = t;
}
}

int so[9], count[9];
int end;

void srch(int now)
{
int i, j, p;
int pos, k;
if(now == 9){
getgrade();
return;
}
i = so[now];
if(count[i] == 0){
srch(now + 1);
return;
}
count[i]--;
p = 511 ^ row[i];
p = p & -p;
row[i] |= p;
j = f[p];

pos = 511 ^ (n_row[i] | n_line[j] | small[getid(i, j)]);
while(pos > 0){
k = pos & -pos;
pos ^= k;
n_row[i] |= k;
n_line[j] |= k;
small[getid(i, j)] |= k;
map[i][j] = f[k] + 1;
srch(now);
n_row[i] ^= k;
n_line[j] ^= k;
small[getid(i, j)] ^= k;
}

count[i]++;
row[i] ^= p;
}

int main(int argc, char **argv)
{
int i, j, t;
for(i = 1, j = 0; i <= 511; i <<= 1, j++){
f[i] = j;
}
for(i = 0; i < 9; i++){
for(j = 0; j < 9; j++){
scanf("%d", &map[i][j]);
if(map[i][j] != 0){
row[i] |= con(j);
t = con(map[i][j] - 1);
if(((n_row[i] & t) != 0) || ((n_line[j] & t) != 0) || ((small[getid(i, j)] & t) != 0)){
printf("-1\n");
return 0;
}
n_row[i] |= t;
n_line[j] |= t;
small[getid(i, j)] |= t;
}else{
count[i]++;
}
}
}
for(i = 0; i < 9; i++){
so[i] = i;
}
for(i = 0; i < 9; i++){
for(j = i + 1; j < 9; j++){
if(count[so[i]] > count[so[j]]){
so[i] ^= so[j];
so[j] ^= so[i];
so[i] ^= so[j];
}
}
}
for(i = 0; count[so[i]] == 0; i++){ ; }
srch(i);
if(ans == 0){
printf("-1\n");
return 0;
}
printf("%d\n", ans);
return 0;
}


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