[DFS]P1074 [NOIP 2009 提高组] 靶形数独 题解

搜索练习题,细节我认为不是很多。

由于暴搜是 \(O(n^n)\) 一个小trick是从0少的层级开始搜索。加上本来有很多填上的数与每一行列块不能填同样数的限制,复杂度完全跑不满。

感觉没啥好讲的,写就完了。有问题看代码吧,都很明了。

#include <bits/stdc++.h>
#define rep(i, a, b) for(int i = a; i <= b; ++i)
using namespace std;
inline int belong(int x, int y) {
	return (x - 1) / 3 * 3 + (y - 1) / 3 + 1;
}
inline int mark(int x, int y) {
	if(x == 1 || y == 1 || x == 9 || y == 9) return 6;
	if(x == 2 || y == 2 || x == 8 || y == 8) return 7;
	if(x == 3 || y == 3 || x == 7 || y == 7) return 8;
	if(x == 4 || y == 4 || x == 6 || y == 6) return 9;
	return 10;
}
pair<int, int> cnt[10], List[100];
bool lie[10][10], hang[10][10], form[10][10];
int a[10][10], tot, ans = -1, sum;
void dfs(int now, int sum) {
	if(now == tot + 1) {//由于会多加1个,所以要判断一下
		ans = max(ans, sum);
		return;
	}
	rep(i, 1, 9) {
		int X = List[now].first, Y = List[now].second;//这里注意不要开成全局变量了!
		if(!lie[Y][i] || !hang[X][i] || !form[belong(X, Y)][i]) {
			continue;
		}
		hang[X][i] = false;
		lie[Y][i] = false;
		form[belong(X, Y)][i] = false;
		dfs(now + 1, sum + i * mark(X, Y));
		hang[X][i] = true;
		lie[Y][i] = true;
		form[belong(X, Y)][i] = true;
	}
}
int main() {
	memset(lie, true, sizeof lie);
	memset(hang, true, sizeof hang);
	memset(form, true, sizeof form);
	rep(i, 1, 9) {
		cnt[i].second = i;
		rep(j, 1, 9) {
			cin >> a[i][j];
			cnt[i].first += !a[i][j];
			sum += a[i][j] * mark(i, j);
			lie[j][a[i][j]] = false;
			hang[i][a[i][j]] = false;
			form[belong(i, j)][a[i][j]] = false;
		}
	}
	sort(cnt + 1, cnt + 10);
	rep(i, 1, 9) {
		rep(j, 1, 9) {
			if(!a[cnt[i].second][j]) {
				List[++tot].first = cnt[i].second, List[tot].second = j;
  //把待搜索的点全部放进去,便于搜索
			}
		}
	}
	dfs(1, sum);
	cout << ans;
	return 0;
}
posted @ 2025-09-01 01:18  風月華  阅读(30)  评论(0)    收藏  举报