D-嘻嘻嘻嘻嘻_一起来做题~欢乐赛7

嘻嘻嘻嘻嘻

https://ac.nowcoder.com/acm/contest/18072/D

D-嘻嘻嘻嘻嘻_一起来做题~欢乐赛7 (nowcoder.com)

题目描述

给一棵m个结点的无根树,你可以选择一个度数大于1的结点作为根,然后给一些结点(根、内部结点和叶子均可)着以黑色或白色。你的着色方案应该保证根结点到每个叶子的简单路径上都至少包含一个有色结点(哪怕是这个叶子本身)。 对于每个叶结点u,定义c[u]为从根结点从U的简单路径上最后一个有色结点的颜色。给出每个c[u]的值,设计着色方案,使得着色结点的个数尽量少。

样例

5 3
0
1
0
1 4
2 5
4 5
3 5
2

算法1

(换根dp)
分析
  • 先考虑有根的树形dp
  • 每一个节点的状态只有三种染成白色,染成黑色,不染色
  • 我们可以围绕这三个状态定义状态方程

状态表示状态计算
  • 定义再以u为根的子树中,将根节点,染成黑色(0)/ 染成白色(1)/ 不染色(2)的所有合法方案的方案中染色次数最少

  • 状态计算:

    1. 节点u染成黑色

      解释:1:将u染成黑色的贡献,:因为u已经染成黑色了所以v就不需要染成黑色了,把将v染成黑色的贡献去掉 -1

    2. 将节点u染成白色

      解释:1 :将u染成白色的贡献,因为u已经染成白色了所以v就不需要染成白色了,把将v染成白色的贡献去掉 -1

    3. 节点u不染色


细节:
  1. 叶子节点需要特殊处理,设叶子节点为x

    1. 当c[x] == 0时,叶子节点到根节点路径上第一个节点必须是黑色

      解释:显然叶子节点到根节点路径上第一个节点必须是黑色,那么将叶子节点染成黑色是合法的,贡献为1

      显然叶子节点到根节点路径上第一个节点必须是黑色,那么将叶子节点染成白色是非法的,将它设为INF这样就不会更新答案

      ,不染色合法是指以x为根的子树的所有叶子节点的都被除外的子节点满足了,叶子节点显然没有子节点能满足它所以是 非法的,将它设为INF这样就不会更新答案

    2. 当c[x] == 1时,叶子节点到根节点路径上第一个节点必须是白色

      解释:显然叶子节点到根节点路径上第一个节点必须是白色,那么将叶子节点染成黑色是非法的,将它设为INF这样就不会更新答案

      显然叶子节点到根节点路径上第一个节点必须是白色,那么将叶子节点染成白色是合法的,贡献为1

      ,不染色合法是指以x为根的子树的所有叶子节点的都被除外的子节点满足了,叶子节点显然没有子节点能满足它所以是 非法的,将它设为INF这样就不会更新答案

时间复杂度

参考文献

C++ 代码

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
// #include <unordered_map>
#include <vector>
#include <queue>
#include <set>
#include <bitset>
#include <cmath>
#include <map>

#define x first
#define y second

#define P 131

#define lc u << 1
#define rc u << 1 | 1

using namespace std;
typedef long long LL;
const int N = 100010;
const int INF = 0x3f3f3f3f;
int h[N],ne[N * 2],e[N * 2],idx;
int color[N];
int c[N];
int f[N][3];
int ans;
int n,m;

void add(int a,int b)
{
    e[idx] = b,ne[idx] = h[a],h[a] = idx ++;
}

void dfs1(int u,int father)
{
    if(u <= m)
    {
        f[u][0] = (c[u]==0)?1:INF,f[u][1] = (c[u] == 1)?1:INF,f[u][2] = INF;
    }else
    {
        f[u][0] = 1,f[u][1] = 1;
        for(int i = h[u];~i;i = ne[i])
        {
            int j = e[i];
            if(j == father) continue;
            dfs1(j,u);
            f[u][0] += min(min(f[j][0] - 1,f[j][1]),f[j][2]);
            f[u][1] += min(min(f[j][0],f[j][1] - 1),f[j][2]);
            f[u][2] += min(min(f[j][0],f[j][1]),f[j][2]);
        }
    }
}

void dfs2(int u,int father)
{
    if(u > m)
    {

        for(int i = h[u];~i;i = ne[i])
        {
            int j = e[i];
            if(j == father) continue;
            int t0,t1,t2;
            t0 = f[u][0] - min(min(f[j][0] - 1,f[j][1]),f[j][2]);
            t1 = f[u][1] - min(min(f[j][0],f[j][1] - 1),f[j][2]);
            t2 = f[u][2] - min(min(f[j][0],f[j][1]),f[j][2]);
            f[j][0] += min(min(t0 - 1,t1),t2);
            f[j][1] += min(min(t0,t1 - 1),t2);
            f[j][2] += min(min(t0,t1),t2);
            dfs2(j,u);
        }
        ans = min(ans,min(min(f[u][0],f[u][1]),f[u][2]));
    }
}

void solve()
{
    scanf("%d%d",&n,&m);
    for(int i = 1;i <= n;i ++) h[i] = -1;
    for(int i = 1;i <= m;i ++) scanf("%d",&c[i]);
    for(int i = 0;i < n - 1;i ++)
    {
        int a,b;
        scanf("%d%d",&a,&b);
        add(a,b);
        add(b,a);
    }
    ans = INF;
    dfs1(m + 1,0);
    // cout << f[m + 1][2] << endl;
    dfs2(m + 1,0);
    printf("%lld\n",ans);
} 

int main()
{
    int _ = 1;

    // freopen("network.in","r",stdin);
    // freopen("network.out","w",stdout);
    // init(N - 1); 

    // std::ios_base::sync_with_stdio(0);
    // cin.tie(0);
    // cin >> _;

    // scanf("%d",&_);
    while(_ --)
    {
        // scanf("%lld%lld",&n,&m);
        solve();
        // test();
    }
    return 0;
}
全部评论

相关推荐

特斯联 后端开发 300 + 450餐补
点赞 评论 收藏
转发
#简历#先说一说我自己的想法,很多人都很排斥苍穹外卖,认为没什么技术点和含金量,但实际上我觉得恰恰相反,苍穹外卖虽然代码本身并不是你自身能力的证明,但是是作为一个新人学习时很好的跳板和原始框架,在这个框架上进行的改进可以很好的辐射到你自己的个人成果上,并作为你和面试官聊天的筹码大多数人的苍穹外卖只写增删改查,千篇一律,吸引不了面试官,所以这才让大家误以为只要是苍穹外卖就不要写进简历里这种误区,但实际上如果你在原有的层面上进行改进,并作为你的项目亮点和面试官介绍,告诉他你的苍穹外卖和别人的有什么不同,增加了哪些技术难点,这才显得你是完全自己理解了这个项目,并且有自己动手实践项目的能力,而不是就看了个课程就以为自己会了,就当成自己的了,如此一来,这反而成为你的加分项苍穹外卖为什么看的人最多,说明它好啊,如果它不好,为什么看的人还这么多,想清楚这个逻辑,我觉得要做的最重要的事,就是如何在原有框架上进行改进提效,比起听其他人的话重新搞一个项目性价比高得多,而且我亲测项目并没有成为我找到工作的阻碍,我投的大厂一大半都给我面试了,而且很多不止一个部门,退一万步说,当你手头没有其他项目的时候,有苍穹外卖总比什么都没有的好很多,不需要因为苍穹外卖有任何心理负担关于简历的任何部分都欢迎大家提意见,十分感谢大家,祝大家找实习+秋招顺利上岸,offer拿到手软#简历中的项目经历要怎么写##我的上岸简历长这样##最后再改一次简历##简历##简历被挂麻了,求建议#
点赞 评论 收藏
转发
5 收藏 评论
分享
牛客网
牛客企业服务