NOIP 2009 靶形数独 解题报告
就是用位运算,直接读出一行中应该放的位置和该放的数字,然后枚举。但不是随意的枚举,要从已经填的最多的那行开始搜,最后搜内容最空白的一行,至于为什么呢?想一想吧,一行中要填的空白多(就是已经填的很少),那每个个子里面可以装的数字就越多,相反,需要填写的很少,那么枚举的情况就少。就是说比如第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; }