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;
}

  

posted @ 2011-08-10 16:24  zqynux  阅读(2322)  评论(0编辑  收藏  举报