靶形数独

题目描述

思路

一开始,觉得应该对每个格子为0的进行dfs,为了进行顺序最优的dfs,要先从可选数量少的格子进行,这样对每个格子创建一个set,存储能够填的数。
然后就是根据size大小排序,选择最小的进行dfs。
然后发现每次dfs都要进行排序,set的二维数组得设在dfs函数内,排序的时候又得根据这个set数组的大小进行排序,对于cmp函数内访问的set应该是全局变量,又得设置一个全局变量的set二维数组保存每次dfs函数内创建的set数组,然后排序。
然后发现每次dfs只会选择数据量最小的进行排序,这样就不用使用二维数组,直接遍历的时候筛选处数据量最小的set就可以了。
然后就是这样做了之后,忘记判断有无解的情况,之后就是wrong answeer。
然后就是time limit exceed,按照书上说的dfs剪枝技巧,最起码现在完成了最优搜索顺序。
然后就是每次填数字其实影响的就只有行,列和小九宫格里面的数据选择,更新全部的话,显得重复,不更新全部,代码有点难写。dfs就麻烦在剪枝上,剪不掉就会造成超时,真烦人。
然后就是可以采用状态压缩的方式保存格子的数据选择集合。
然后就是去掉set,改用位运算的方式实现上述的算法,终于过了,可见set是多么的耗时。

代码

#include <cstdio>
#include <cstring>

int mp[9][9], ans;
const int wq = 511;
bool flag = false;
int val[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, 
};
bool get(int x, int y, int &z) {
	int k = 0;
	for (int i = 0; i < 9; ++i) {
		if (mp[x][i] != 0) k |= 1 << (mp[x][i] - 1);
		if (mp[i][y] != 0) k |= 1 << (mp[i][y] - 1);
	}
	int a = x / 3 * 3, b = y / 3 * 3;
	for (int i = 0; i < 3; ++i) {
		for (int j = 0; j < 3; ++j) {
			if (mp[a + i][b + j] != 0) k |= 1 << (mp[a + i][b + j] - 1);
		}
	}
	z = wq ^ k;
	return z == 0;
}

int getbit(int x) {
	int y = 0;
	while (x) {
		if (x & 1) ++y;
		x >>= 1;
	}
	return y;
}
bool mysort(int &x, int &y, int &z) {
	z = wq;
	int b = 0;
	for (int i = 0; i < 9; ++i) {
		for (int j = 0; j < 9; ++j) {
			if (mp[i][j] == 0) {
				if (get(i, j, b)) return false;
				if (getbit(b) < getbit(z)) z = b, x = i, y = j;
			}
		}
	}
	return true;
}

void dfs(int res) {
	int x, y, z = 0;
	if (!mysort(x, y, z)) return;
	if (getbit(z) == 9) {
		flag = true;
		if (res > ans) ans = res;
		return;
	}
	int k = 0;
	while (z) {
		if (z & 1) {
			mp[x][y] = k + 1;
			dfs(res + mp[x][y] * val[x][y]);
			mp[x][y] = 0;
		}
		z >>= 1;
		k++;
	}
}
int main() {
	for (int i = 0; i < 9; ++i) {
		for (int j = 0; j < 9; ++j) {
			scanf("%d", &mp[i][j]);
			if (mp[i][j] != 0) ans += mp[i][j] * val[i][j];
		}
	}
	dfs(ans);
	if (flag) printf("%d\n", ans);
	else puts("-1");
	return 0;
}
posted @ 2019-09-30 16:19  cabbage-leaf  阅读(285)  评论(0编辑  收藏  举报