• 周五. 4月 26th, 2024

5G编程聚合网

5G时代下一个聚合的编程学习网

热门标签

红黑树

admin

11月 28, 2021

题目背景

小 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\% 的数据,1leq nleq 51≤n≤5)
(对于 30\% 的数据,1leq nleq 101≤n≤10)
$对于另外 20% 的数据,forall a_i
eq b_i (
)
对于 100% 的数据,1leq nleq 20,1leq Qleq 20,树随机生成$

题目解析

根据n<=20,首先是状态压缩

然后是通过预处理数组(pre)表示翻转(j)经过(i)秒后的树状态

最后是通过状态压缩动态规划,对每秒进行的操作进行转移。

因为一次操作的影响是持续的,对于转移状态的表示造成了困难,所以考虑转换思路

对于时间t,要么直接跳过(dp[t+1][s]=1),要么直接时间以(dp[t+1][sigoplus 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(); 
    }
}

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注