红黑树
作者:互联网
题目背景
小 M 迷上了画画,所以她用红色和黑色的画笔画出了一棵红黑树。
题目描述
这棵树有 n 个点,从 11 开始标号,其中 11 号点为树根。一开始,小 M 给这 n 个点分别涂上了红色或黑色,第 i号点的颜色是 a_i('R' 代表红色,'B' 代表黑色)。
但可惜的是,小 M 对这棵树并不是非常满意,她希望第 i 号点的颜色为 b_i
好在她的好朋友小 K 懂得一点点膜法。小 K 可以先选定一个点,然后把这个点的颜色反转(红变黑,黑变红)。但这个膜法太强大了,所以会把膜法传递下去,即在反转的一秒之后使当前点的父节点颜色也进行反转,如此传递,直到根节点为止。特殊的,如果在同一时刻有多个膜法作用在同一个点上,这些膜法会两两抵消,如果恰好抵消完了(即膜法的个数为偶数),则当前点不会变色,并且不会有膜法继续传递下去。注意此处抵消膜法不需要耗时间。
但毕竟小 K 还是个新手,所以他在一秒之内只能最多对一个节点施展上述膜法。
为了尽快让小 M 开心,小 K 想知道,至少经过多少秒才能让这棵红黑树初次出现小 M 的理想颜色状态?可以证明,总可以按题目要求变成理想颜色状态。
输入格式
本题多测。
第一行一个整数 Q,表示数据组数。
对于每组数据:
第一行一个整数 n,表示红黑树的节点数。
第二行一个长度为 n 的字符串 a,表示红黑树的初始颜色状态,其中仅含有 'R' 或 'B'。
接下来 n-1 行,每行两个整数 x,y描述一条树边。
最后一行一个长度为 n 的字符串 b,表示红黑树的理想颜色状态,其中仅含有 'R' 或 'B'。
输出格式
共 Q 行每行一个整数,一组数据一行,表示答案,即最小耗时。
输入输出样例
输入 #1
2
5
RRBBR
1 2
1 3
2 4
2 5
BRBRB
5
RRRRR
1 2
2 3
3 4
4 5
BBBBB
输出 #1
3
3
说明/提示
【样例解释】
第一组数据中,小 K 可以在第 1秒给 4 号点膜法,整个树变为 RRBRR,在第 2 秒给 5 号点膜法,整个树变成 RBBRB,在第 3 秒给 1 号点膜法,整个树变成 BRBRB。
第二组数据中,小 K 可以在第 1 秒给 5 号点膜法,在第二秒给 2 号点膜法;或者在第 1 秒给 3 号点膜法,在第 2 秒给 5 号点膜法。
【数据范围】
\(对于 10\% 的数据,1\leq n\leq 51≤n≤5\)
\(对于 30\% 的数据,1\leq n\leq 101≤n≤10\)
$对于另外 20% 的数据,\forall a_i\neq b_i \(
\)对于 100% 的数据,1\leq n\leq 20,1\leq Q\leq 20,树随机生成$
题目解析
根据n<=20,首先是状态压缩
然后是通过预处理数组\(pre\)表示翻转\(j\)经过\(i\)秒后的树状态
最后是通过状态压缩动态规划,对每秒进行的操作进行转移。
因为一次操作的影响是持续的,对于转移状态的表示造成了困难,所以考虑转换思路
对于时间t,要么直接跳过\(dp[t+1][s]=1\),要么直接时间以\(dp[t+1][s\bigoplus pre[t][i]]=1\)转移
这种转移看起来不合理,因为时间\(t\)的\(pre[t][i]\)表示从\(0\)时刻到\(t\)时刻的翻转影响,那么\([1,t]\)时刻的其他翻转事件如何处理?
答案在于之前的转移,当时间为\([0,t-1]\)时,转移了持续时间为\([0,t-1]\)的翻转事件,可以视作转移从时刻\([2,t]\)开始的翻转事件。如\(pre[t-1][j]\)实际上表示\(j\)从\(1\)时刻到\(t\)时刻的翻转
即:前面时刻的状态转移模拟的是后面时刻的操作影响
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
struct Node
{
int next, to;
} edge[25];
int head[25];
int dp[21][1024 * 1024 + 5], n, num,fa[25];
int sstatus, estatus;
//预处理pre[i][j]表示翻转j经过i秒后的状态
int pre[21][1024*1024+5];
char str[21];
void add(int x, int y)
{
num++;
edge[num].next = head[x];
head[x] = num;
edge[num].to = y;
fa[y]=x;
}
int getStatus(char *str)
{
int status = 0;
for (int i = 0; i < n; i++)
{
if (str[i] == 'B')
status |= (1 << i);
}
return status;
}
void getColorChange(){
for (int i=1;i<=n;i++){
pre[0][i]=1<<(i-1);
}
for (int t=1;t<n;t++){
for (int i=1;i<=n;i++){
pre[t][i]=pre[t-1][fa[i]]|(1<<(i-1));
}
}
}
void DP(){
dp[0][sstatus]=1;
for (int t=0;t<n;t++){
if (dp[t][estatus]){
cout<<t<<endl;
return;
}
for (int s=0;s<(1<<n);s++)
if (dp[t][s]){
dp[t+1][s]=1;
for (int i=1;i<=n;i++)
dp[t+1][s^pre[t][i]]=1;
}
}
cout<<-1<<endl;
}
int main()
{
int T, x, y;
cin >> T;
while (T--)
{
cin >> n;
memset(head, 0, sizeof(head));
memset(dp,0,sizeof(dp));
cin >> str;
num = 0;
sstatus = getStatus(str);
for (int i = 1; i < n; i++)
{
scanf("%d%d", &x, &y);
add(x, y);
}
cin >> str;
estatus=getStatus(str);
getColorChange();
DP();
}
}
标签:膜法,int,leq,num,str,红黑树,号点 来源: https://www.cnblogs.com/Y-E-T-I/p/15129807.html