解题思路
-
核心思想:
- 使用 数组标记配对关系: 表示节点 和 需要染成相同颜色
- 通过两次DFS完成配对和染色
-
第一次DFS (dfs1):确定配对关系
- 从根节点开始,自底向上处理
- 对于叶子节点或未配对的节点:
- 如果其父节点已配对,则无解
- 否则,将该节点与其父节点配对(赋予相同的 值)
- 配对号 从 开始递增
-
第二次DFS (dfs2):根据配对关系染色
- 从根节点开始,自顶向下染色
- 如果两个节点配对号相同,则染相同颜色
- 如果配对号不同,则染相反颜色
代码
#include <bits/stdc++.h>
using namespace std;
const int N = 100010;
int n, cnt = 0;
vector<int> g[N];
int f[N], col[N]; // f:配对关系, col:颜色
bool valid = true;
void dfs1(int x, int fa) {
int son = 0;
// 遍历所有子节点
for(int y : g[x]) {
if(y == fa) continue;
son++;
dfs1(y, x);
}
// 如果是叶子节点或未配对的节点
if(son == 0 || f[x] == 0) {
if(f[fa] != 0) { // 如果父节点已配对,无解
valid = false;
return;
}
f[x] = f[fa] = ++cnt; // 与父节点配对
}
}
void dfs2(int x, int fa) {
for(int y : g[x]) {
if(y == fa) continue;
// 根据配对关系染色
col[y] = (f[y] == f[x]) ? col[x] : (col[x] ^ 1);
dfs2(y, x);
}
}
int main() {
cin >> n;
// 建图
for(int i = 1; i < n; i++) {
int x, y;
cin >> x >> y;
g[x].push_back(y);
g[y].push_back(x);
}
dfs1(1, 0);
// 检查是否有解
if(f[0] != 0 || !valid) {
cout << "-1" << endl;
return 0;
}
// 从根节点开始染色
col[1] = 1;
dfs2(1, 0);
// 输出结果
for(int i = 1; i <= n; i++) {
cout << (col[i] == 1 ? 'R' : 'B');
}
cout << endl;
return 0;
}
import java.util.*;
public class Main {
static int N = 100010;
static int n, cnt;
static ArrayList<Integer>[] g;
static int[] f; // 配对关系
static int[] col; // 颜色
static boolean valid = true;
static void dfs1(int x, int fa) {
int son = 0;
// 遍历所有子节点
for(int y : g[x]) {
if(y == fa) continue;
son++;
dfs1(y, x);
}
// 如果是叶子节点或未配对的节点
if(son == 0 || f[x] == 0) {
if(f[fa] != 0) { // 如果父节点已配对,无解
valid = false;
return;
}
f[x] = f[fa] = ++cnt; // 与父节点配对
}
}
static void dfs2(int x, int fa) {
for(int y : g[x]) {
if(y == fa) continue;
// 根据配对关系染色
col[y] = (f[y] == f[x]) ? col[x] : (col[x] ^ 1);
dfs2(y, x);
}
}
@SuppressWarnings("unchecked")
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
n = sc.nextInt();
// 初始化
g = new ArrayList[N];
for(int i = 0; i < N; i++) {
g[i] = new ArrayList<>();
}
f = new int[N];
col = new int[N];
// 建图
for(int i = 1; i < n; i++) {
int x = sc.nextInt();
int y = sc.nextInt();
g[x].add(y);
g[y].add(x);
}
dfs1(1, 0);
// 检查是否有解
if(f[0] != 0 || !valid) {
System.out.println("-1");
return;
}
// 从根节点开始染色
col[1] = 1;
dfs2(1, 0);
// 输出结果
StringBuilder sb = new StringBuilder();
for(int i = 1; i <= n; i++) {
sb.append(col[i] == 1 ? 'R' : 'B');
}
System.out.println(sb.toString());
sc.close();
}
}
import sys
sys.setrecursionlimit(100010)
def dfs1(x, fa, g, f, cnt):
son = 0
# 遍历所有子节点
for y in g[x]:
if y == fa:
continue
son += 1
dfs1(y, x, g, f, cnt)
# 如果是叶子节点或未配对的节点
if son == 0 or f[x] == 0:
if f[fa] != 0: # 如果父节点已配对,无解
return False
cnt[0] += 1
f[x] = f[fa] = cnt[0] # 与父节点配对
return True
def dfs2(x, fa, g, f, col):
for y in g[x]:
if y == fa:
continue
# 根据配对关系染色
col[y] = col[x] if f[y] == f[x] else (col[x] ^ 1)
dfs2(y, x, g, f, col)
def main():
n = int(input())
# 建图
g = [[] for _ in range(n+1)]
for _ in range(n-1):
x, y = map(int, input().split())
g[x].append(y)
g[y].append(x)
# 初始化
f = [0] * (n+1) # 配对关系
col = [0] * (n+1) # 颜色
cnt = [0] # 使用列表传递引用
# 第一次DFS确定配对关系
if not dfs1(1, 0, g, f, cnt) or f[0] != 0:
print("-1")
return
# 从根节点开始染色
col[1] = 1
dfs2(1, 0, g, f, col)
# 输出结果
print(''.join('R' if c == 1 else 'B' for c in col[1:n+1]))
if __name__ == "__main__":
main()
算法及复杂度
- 算法:两次DFS
- 时间复杂度:,需要两次遍历树
- 空间复杂度:,用于存储图、配对关系和颜色