【染色问题】题解
2025-07-20 10:41:45
发布于:广东
7阅读
0回复
0点赞
题干信息解读
给定一个由黑色(#)和白色(.)组成的 n 行 m 列矩阵,你可以选择若干行和列染成红色。染色后,被选中的行和列中的所有格子都会变为红色。要求计算有多少种不同的行列选择方案,使得染色后的矩阵中恰好剩下 k 个黑色格子。
整体做题思路
枚举所有可能的行和列选择:由于 n 和 m 的范围较小(最大为 6),可以使用位运算枚举所有可能的行和列组合。
计算剩余黑色格子数:对于每一种行列组合,计算未被选中的行和列的交叉点中原本就是黑色的格子数量。
统计符合条件的方案数:检查每种组合下剩余的黑色格子数是否等于 k,若是则计入答案。
难点和注意事项
位运算的应用:使用位掩码(bitmask)来枚举所有可能的行和列选择,每个位表示对应的行或列是否被选中。
剩余黑色格子的计算:需要确保只计算未被选中的行和列交叉点中的黑色格子。
时间复杂度的控制:由于 n 和 m 较小,枚举所有组合的时间复杂度为 O (2^(n+m)),是可行的。
AC代码(如有雷同,纯属巧合)
#include <iostream>
#include <vector>
#include <string>
using namespace std;
int main() {
int n, m, k;
cin >> n >> m >> k;
vector<string> matrix(n);
for (int i = 0; i < n; ++i) {
cin >> matrix[i];
}
int ans = 0;
// 枚举所有行的选择情况(0到2^n-1)
for (int row_mask = 0; row_mask < (1 << n); ++row_mask) {
// 枚举所有列的选择情况(0到2^m-1)
for (int col_mask = 0; col_mask < (1 << m); ++col_mask) {
int cnt = 0;
// 遍历每个格子,检查是否为未被选中的行和列的交叉点
for (int i = 0; i < n; ++i) {
for (int j = 0; j < m; ++j) {
// 如果行i和列j都未被选中,并且原本是黑色格子
if (((row_mask & (1 << i)) == 0) && ((col_mask & (1 << j)) == 0) && matrix[i][j] == '#') {
cnt++;
}
}
}
// 如果剩余黑色格子数等于k,方案数加1
if (cnt == k) {
ans++;
}
}
}
cout << ans << endl;
return 0;
}
复杂度分析
时间复杂度:O (2^)。枚举所有行和列的组合需要 O () = O (2^(n+m)),对于每种组合,遍历所有格子需要 O ()。
空间复杂度:O ()。主要用于存储输入的矩阵。
该算法通过位运算高效枚举所有可能的行列组合,并直接计算剩余黑色格子数,确保在小规模数据下的高效性。
全部评论 2
留下一个小赞
证明你来过
2025-07-20 来自 广东
1这么优秀的题解,必须顶好吧!!
2025-07-20 来自 广东
1
有帮助,赞一个