洛谷P1074 靶形数独(DFS)

传送门 难度
https://www.luogu.com.cn/problem/P1074 提高+/省选-

分析

  • 就是一道DFS的题目,但是需要技巧,不然就会超时(数据挺恶心很容易TLE)
  • 玩数独的一般都会找可以确定的格子或者基本可以确定的格子开始。同样,本题的技巧就是先找约束最多的点然后再DFS,这样就可以减少搜索的次数。
  • 可以列出来的就先列出来,别浪费时间调用函数计算了。
  • 求和可以变递归边计算,也可以放到最后一块儿算。区别不大,放到最后一块儿算略快一点。(所有测试点一共差了0.1s左右)

AC代码1

#include
#include
#include
#include

using namespace std;

const int N = 9;

bool line[N][N + 1];
bool col[N][N + 1];
bool r[N][N + 1];
const int cellindex[N][N] =
{{0,0,0,1,1,1,2,2,2},
{0,0,0,1,1,1,2,2,2},
{0,0,0,1,1,1,2,2,2},
{3,3,3,4,4,4,5,5,5},
{3,3,3,4,4,4,5,5,5},
{3,3,3,4,4,4,5,5,5},
{6,6,6,7,7,7,8,8,8},
{6,6,6,7,7,7,8,8,8},
{6,6,6,7,7,7,8,8,8}};
int shudu[N][N];
const int w[N][N] =
{{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 res = -1;
bool visit[N][N];


inline void record() {
	int sum = 0;
	for (int i = 0; i < N; ++i)
		for (int j = 0; j < N; ++j)
			sum += shudu[i][j] * w[i][j];
	if (sum > res)
		res = sum;
}


inline void dfs(int cur) {
	if (cur == 81) {
		record();
		return;
	}
	int xx = 0, yy = 0 , minrule = 233, cnt;
	for (int i = 0; i < N; ++i) {
		for (int j = 0; j < N; ++j) {
			if (visit[i][j])
				continue;
			cnt = 0;
			for (int k = 1; k <= 9; ++k)
				if (!line[i][k] && !col[j][k] && !r[cellindex[i][j]][k])
					cnt++;
			if (cnt < minrule) {
				minrule = cnt;
				xx = i;
				yy = j;
			}
		}
	}
	int op = cellindex[xx][yy];
	for (int i = 1; i <= 9; ++i)
		if (!line[xx][i] && !col[yy][i] && !r[op][i]) {
			line[xx][i] = col[yy][i] = r[op][i] = visit[xx][yy] = true;
			shudu[xx][yy] = i;
			dfs(cur + 1);
			line[xx][i] = col[yy][i] = r[op][i] = visit[xx][yy] = false;
		}

}

int main() {
	int usednum = 0;
	int sum = 0;
	for (int i = 0; i < N; ++i){
		for (int j = 0; j < N; ++j){
			scanf("%d", &shudu[i][j]);
			if (shudu[i][j] != 0) {
				usednum++;
				//sum += w[i][j] * shudu[i][j];
				line[i][shudu[i][j]] = true;
				col[j][shudu[i][j]] = true;
				r[cellindex[i][j]][shudu[i][j]] = true;
				visit[i][j] = true;
			}
		}
	}
	dfs(usednum);
	cout << res << endl;
	return 0;
}

AC代码2

状压了一下,好像没啥用。。还出现了一个1.02s的TLE。。。开了O2倒是挺快的

#include
#include
#include
#include

using namespace std;

const int N = 9;
int line[N];
int col[N];
int r[N];
int shudu[N][N];
const int w[N][N] =
{ {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 res = -1;
const int cellindex[N][N] =
{ {0,0,0,1,1,1,2,2,2},
{0,0,0,1,1,1,2,2,2},
{0,0,0,1,1,1,2,2,2},
{3,3,3,4,4,4,5,5,5},
{3,3,3,4,4,4,5,5,5},
{3,3,3,4,4,4,5,5,5},
{6,6,6,7,7,7,8,8,8},
{6,6,6,7,7,7,8,8,8},
{6,6,6,7,7,7,8,8,8} };

inline void record() {
	int sum = 0;
	for (int i = 0; i < N; ++i)
		for (int j = 0; j < N; ++j)
			sum += shudu[i][j] * w[i][j];
	if (sum > res)
		res = sum;
}

inline bool check(int x, int y, int num) {
	int tem = 1 << (num - 1);
	if (line[x] & tem || col[y] & tem || r[cellindex[x][y]] & tem)
		return false;
	return true;
}


void dfs(int cur) {
	if (cur == 81) {
		record();
		return;
	}
	int xx = 0, yy = 0, minrule = 233, cnt;
	for (int i = 0; i < N; ++i) {
		for (int j = 0; j < N; ++j) {
			if (shudu[i][j])
				continue;
			cnt = 0;
			int ktem;
			for (int k = 1; k <= 9; ++k) {
				ktem = 1 << (k - 1);
				if (!(line[i]&ktem) && !(col[j]&ktem) && !(r[cellindex[i][j]] & ktem))
					cnt++;
			}
			if (cnt < minrule) {
				minrule = cnt;
				xx = i;
				yy = j;
			}
		}
	}
	int op = cellindex[xx][yy];
	for (int i = 1; i <= 9; ++i)
		if (check(xx,yy,i)) {
			int tem = 1 << (i - 1);
			line[xx] |= tem;
			col[yy] |= tem; 
			r[op] |= tem;
			shudu[xx][yy] = i;
			dfs(cur + 1);
			tem = ~(tem);
			line[xx] &= tem;
			col[yy] &= tem;
			r[op] &= tem;
			shudu[xx][yy] = 0;
		}

}
int main() {
	int usednum = 0;
	int sum = 0;
	for (int i = 0; i < N; ++i) {
		for (int j = 0; j < N; ++j) {
			scanf("%d", &shudu[i][j]);
			if (shudu[i][j]) {
				usednum++;
				int ctem = 1 << (shudu[i][j] - 1);
				line[i] |= ctem;
				col[j] |= ctem;
				r[cellindex[i][j]] |= ctem;
			}
		}
	}
	dfs(usednum);
	cout << res << endl;
	return 0;
}

你可能感兴趣的:(DFS)