CF1638D - Big Brush(构造性算法 + 数据结构 + 贪心 + 模拟 / 铁牌级)

1638D - Big Brush(源地址自⇔CF1638D


tag

⇔构造性算法、⇔数据结构、⇔贪心、⇔模拟、⇔铁牌级(*2000)

题意

在一张 \(N *M\) 的画布上涂颜色,规定涂色操作如下:

  • 最初的画布是没有颜色的;

  • 画笔一次性对 \(2*2\) 的正方形涂色——对于选中的 \((i, j)\) 位置,同时对 \((i+1,j),(i,j+1),(i+1,j+1)\) 涂上颜色;

  • 保证所有的格子都会被涂上颜色,一个格子可以被多次涂色。

现在要求你找到一种可能的涂色方法,并且输出步骤(注意,不能超过 \(N*M\) 次)。

思路

概要:很容易的,可以找到最后一下涂色涂的位置,而这个位置下所掩盖的颜色是不确定的,所以,我们发现可以通过逆推找到涂色的顺序。

不妨将被掩盖的格子定义为“万能格”,这些格子的颜色可以通过边上的格子来确定(如图,我们可以通过三块红颜色的格子推断“?万能格“的颜色也为红色)。那么相应的,只需要暴力枚举每一种情况,就一定能得到一种可行解。模拟分析后可以知道,对于下方粉色的”万能格“,至多需要枚举 \(8\) 种情况,而这样的万能格数量至多为 \(N*M\) 个,故该算法的复杂度为 \(\mathcal{O}(N*M)\) ,可解。

AC代码

点击查看代码
//====================
int n, m, a[1010][1010];
bool Ans;
vector<tuple<int, int, int> > ans;
queue<pair<int, int> > q;
//====================
void check(int x, int y) {
	if(x < 1 || x >= n || y < 1 || y >= m) return;
	if(a[x][y] + a[x + 1][y] + a[x][y + 1] + a[x + 1][y + 1] == 0) return;
	
	int color = max(a[x][y], max(a[x + 1][y], max(a[x][y + 1], a[x + 1][y + 1])));
	if(a[x][y] != 0 && a[x][y] != color) return;
	if(a[x + 1][y] != 0 && a[x + 1][y] != color) return;
	if(a[x][y + 1] != 0 && a[x][y + 1] != color) return;
	if(a[x + 1][y + 1] != 0 && a[x + 1][y + 1] != color) return;
	
	q.push({x, y});
}
void Clear() {
	
}
void Solve() {
	cin >> n >> m;
	FOR(i, 1, n) FOR(j, 1, m) cin >> a[i][j];
	
	FOR(i, 1, n - 1) {
		FOR(j, 1, m - 1) {
			if(a[i][j] == a[i + 1][j] && a[i][j] == a[i][j + 1] && a[i][j] == a[i + 1][j + 1]) {
				q.push({i, j});
			}
		}
	}
	
	while(!q.empty()) {
		auto [x, y] = q.front();
		q.pop();
		
		if(a[x][y] + a[x + 1][y] + a[x][y + 1] + a[x + 1][y + 1] == 0) continue;
		int color = max(a[x][y], max(a[x + 1][y], max(a[x][y + 1], a[x + 1][y + 1])));
		ans.pb({x, y, color});
		a[x][y] = a[x + 1][y] = a[x][y + 1] = a[x + 1][y + 1] = 0;
		
		check(x - 1, y - 1);
		check(x - 1, y);
		check(x - 1, y + 1);
		check(x, y - 1);
		check(x, y + 1);
		check(x + 1, y - 1);
		check(x + 1, y);
		check(x + 1, y + 1);
	}
	
	FOR(i, 1, n) {
		FOR(j, 1, m) {
			if(a[i][j] != 0) {
				cout << -1 << endl;
				return;
			}
		}
	}
	
	reverse(ans.begin(), ans.end());
	cout << ans.size() << endl;
	for(auto [x, y, z] : ans) cout << x << " " << y << " " << z << endl;
}

错误次数

无。


文 / WIDA
2022.02.22 成文
首发于WIDA个人博客,仅供学习讨论


更新日记:
2022.02.22 成文


posted @ 2022-02-22 21:30  hh2048  阅读(145)  评论(0编辑  收藏  举报