华为OD机试题库《C++》限时优惠 9.9
华为OD机试题库《Python》限时优惠 9.9
华为OD机试题库《JavaScript》限时优惠 9.9
针对刷题难,效率慢,我们提供一对一算法辅导, 针对个人情况定制化的提高计划(全称1V1效率更高)。
看不懂有疑问需要答疑辅导欢迎私VX: code5bug
题目描述
众所周知红黑树是一种平衡树,它最突出的特性就是不能有两个相邻的红色节点。那我们定义一个红黑图,也就是一张无向图中,每个节点可能有红黑两种颜色,但我们必须保证没有两个相邻的红色节点。
现在给出一张未染色的图,只能染红黑两色,问总共有多少种染色方案使得它成为一个红黑图。
输入描述
第一行两个数字n m,表示图中有n个节点和m条边。
接下来共计m行,每行两个数字st,表示一条连接节点s和节点t的边,节点编号为[0,n)。
输出描述
一个数字表示总的染色方案数。
补充说明
- 0 < n < 15
- 0 <= m <= n * 3
- 0 <= s,t < n
- 不保证图连通, 保证没有重边和自环
示例1
输入:
3 3
0 1
0 2
1 2
输出:
4
示例2
输入:
4 3
0 1
0 2
1 2
输出:
8
题解
题目类型:
这道题目属于 位运算 和 枚举 类型的题目,结合了图的染色问题,主要通过枚举所有可能的染色方案来判断是否满足约束条件。
解题思路:
- 题目理解:
- 给定一个无向图,图中的每个节点要么是红色,要么是黑色,且相邻的两个节点不能同时为红色。
- 需要计算出图中满足染色条件的所有方案的个数。
- 枚举所有可能的染色方案:
- 假设有
n
个节点,那么可以用一个二进制数表示所有节点的颜色方案。
- 二进制数的每一位表示一个节点的颜色(0 为黑色,1 为红色)。
- 例如,对于
n = 3
,染色方案可以是:
000
(黑色、黑色、黑色)001
(黑色、黑色、红色)010
(黑色、红色、黑色)111
(红色、红色、红色)等。- 检查染色是否合法:
- 对于每一个染色方案,检查是否满足相邻节点不能同时为红色的约束。
- 如果满足条件,则增加计数。
- 算法实现:
- 使用一个二进制数表示每一个染色方案,遍历从
0
到2^n - 1
的所有可能的方案。- 对每一个染色方案,通过位运算提取节点的颜色,检查相邻节点的颜色是否满足条件。
代码大致描述:
- 输入:
- 输入包括节点数
n
和边数m
,接着输入m
条边,每条边表示一对相邻的节点。- 检查染色方案的有效性:
- 对于每个染色方案,检查相邻的节点是否满足约束:即相邻两个节点不能同时为红色(即二进制表示中对应位不能同时为1)。
- 输出:
- 输出符合要求的染色方案的个数。
时间复杂度:
时间复杂度:
我们枚举所有的染色方案,染色方案的总数为
2^n
(即1 << n
)。对于每一个染色方案,我们需要检查所有的边(即
m
条边),对于每条边,需要进行常数时间的操作(位运算)。因此,时间复杂度为: $ O(2^n×m) $
- 由于
n
最大为 15,因此2^n
最多为 32768,m
最大为n * 3 = 45
,所以时间复杂度在最坏情况下是 O(2^n * m) ,即最多约为 1.5 million 次操作,足够在合理时间内完成。空间复杂度:
存储图的边需要
O(m)
的空间。
- 存储染色方案和结果需要
O(1)
空间,除去输入和输出。因此,空间复杂度是
O(m)
。
JavaScript
const rl = require("readline").createInterface({
input: process.stdin
});
var iter = rl[Symbol.asyncIterator]();
const readline = async () => (await iter.next()).value;
function check(edges, plan) {
// 举例: plan 3(二进制:0011) 表示 0,1 号节点为红色, 2,3 号节点黑色
for (let [v1, v2] of edges) {
let c1 = (plan >> v1) & 1; // 找到第 v1 号节点的染色值
let c2 = (plan >> v2) & 1; // # 找到第 v2 号节点的染色值
// 必须保证相邻两个节点不能同时为红色
if (c1 + c2 === 2) return false;
}
return true;
}
// Author: code5bug
void(async function () {
let [n, m] = (await readline()).split(" ").map(Number);
const edges = [];
for (let i = 0; i < m; i++) {
let [v1, v2] = (await readline()).split(" ").map(Number);
edges.push([v1, v2]);
}
// 用二进制位来枚举所有的染色情况,然后统计可行的染色计划
let count = 0;
for (let plan = 0; plan < (1 << n); plan++) {
if (check(edges, plan)) count++;
}
console.log(count);
rl.close();
})();
希望这个专栏能让您熟练掌握算法, 🎁🎁🎁。
整理题解不易, 如果有帮助到您,请给点个赞 ❤️ 和收藏 ⭐,让更多的人看到。🙏🙏🙏