• P7929 [COCI2021-2022#1] Logičari


    P7929 [COCI2021-2022#1] Logičari

    [P7929 COCI2021-2022#1] Logičari - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

    题目大意

    给定一棵 n n n 个节点的基环树,现在对树上的节点染色,使得每个电都有且仅有一个与他相连的点被染色(不包括自身),求最少染色次数,无解输出 − 1 -1 1

    3 ≤ n ≤ 1 0 5 3\le n \le 10^5 3n105

    思路

    我们考虑一棵普通的树看看怎么解决。

    很明显是一个树形 d p dp dp 乱搞就好了。

    我们先 d f s dfs dfs 找到多出来的那条返祖边,设两个端点分别为 S , T S , T S,T

    然后我们考虑不合法的情况:

    1、 S S S 染了,但 T T T 旁边又染了一个。

    2、 T T T 染了,但 T T T 旁边又染了一个。

    3、 S S S 没染, T T T 旁边的那个也没染,而且 T T T 没有其他子树了。

    在遇到 T T T 的时候特判一下就好了。

    我们考虑转移。

    d p [ x ] [ a ] [ b ] dp[x][a][b] dp[x][a][b] 表示现在处理到以 x x x 为根节点的子树, x x x 的状态为 a a a x x x 父亲节点的状态为 b b b 的最小代价。

    w [ x ] [ a ] w[x][a] w[x][a] 表示以 x x x 为根的子树中, x x x 的状态为 a a a 的最小代价。

    v a l = ∑ y = s o n [ x ] w [ y ] [ 0 ] val = \sum_{y = son[x]}w[y][0] val=y=son[x]w[y][0]

    如果 f a [ u ] fa[u] fa[u] 被染了,那么 x x x 的儿子都不能染,所以答案为
    d p [ x ] [ a ] [ b ] = v a l + a dp[x][a][b] = val + a dp[x][a][b]=val+a
    否则
    d p [ x ] [ a ] [ b ] = min ⁡ y = s o n [ x ] ( v a l − w [ y ] [ 0 ] + w [ y ] [ 1 ] ) + a dp[x][a][b] = \min_{y = son[x]}(val - w[y][0] + w[y] [1]) + a dp[x][a][b]=y=son[x]min(valw[y][0]+w[y][1])+a

    code

    #include 
    #define LL long long
    #define fu(x , y , z) for(x = y ; x <= z ; x ++)
    using namespace std;
    const int inf = 1e9 + 5 , N = 1e5 + 5;
    int hd[N] , cnt , s , t , vis[N] , flg , fs , ft , out , n;
    LL f[N][2][2] , w[N][2];
    struct E {
        int to , nt;
    } e[N << 1];
    void add (int x , int y) { e[++cnt].to = y , e[cnt].nt = hd[x] , hd[x] = cnt; }
    void dfs (int x , int fa) {
        int y;
        vis[x] = 1;
        for (int i = hd[x] ; i ; i = e[i].nt) {
            y = e[i].to;
            if (y == fa) continue; 
            if (vis[y]) flg = i;
            else dfs (y , x);
        }
    }
    LL dp (int x , int fa , int a , int b) {
        if (f[x][a][b]) return f[x][a][b];
        int y;
        LL sum = 0 , ans = inf;
        for (int i = hd[x] ; i ; i = e[i].nt) {
            y = e[i].to;
            if ((y == fa) || (i == flg) || ((i ^ 1) == flg)) continue;
            if (y == t) {
                if ((a && fs) || (b && ft) || (!a && !fs && out < 3)) return inf;
                w[y][ft] = dp (y , x , ft , (fs | a));
                w[y][!ft] = inf;
                sum += w[y][0];
            }
            else {
                w[y][0] = dp (y , x , 0 , a);
                sum += w[y][0];
                if (!b) w[y][1] = dp (y , x , 1 , a);
            } 
        }
        if (b) return f[x][a][b] = sum + a;
        for (int i = hd[x] ; i ; i = e[i].nt) {
            y = e[i].to;
            if ((y == fa) || (i == flg) || ((i ^ 1) == flg)) continue;
            ans = min (ans , sum - w[y][0] + w[y][1]);
        }
        return f[x][a][b] = ans + a;
    }
    int main () {
        int x , y;
        LL ans;
        cnt = 1;
        scanf ("%d" , &n);
        for (int i = 1 ; i <= n ; i ++) {
            scanf ("%d%d" , &x , &y);
            add (x , y) , add (y , x);
        }
        dfs (1 , 0);
        s = e[flg].to , t = e[flg ^ 1].to;
        for (int i = hd[t] ; i ; i = e[i].nt) ++out;
        // cout << out << " " << t;
        // return 0;
        fs = ft = 0;
        ans = dp (s , 0 , 0 ,0);
        memset (f , 0 , sizeof (f));
        fs = 1 , ft = 0;
        ans = min (ans , dp (s , 0 , 1 , 0));
        memset (f , 0 , sizeof (f));
        fs = 0 , ft = 1;
        ans = min (ans , dp (s , 0 , 0 , 1));
        memset (f , 0 , sizeof (f));
        fs = ft = 1;
        ans = min (ans , dp (s , 0 , 1 , 1));
        if (ans <= 1ll * n) printf ("%lld" , ans);
        else printf ("-1");
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
  • 相关阅读:
    4年北漂之路,从软件测试外包到外企的一点小心得
    多线程学习-线程池
    【Java 快速复习】垃圾回收算法 & 垃圾回收器
    海外版知乎Quora,如何使用Quora进行营销?
    摩天大楼记录
    攻防世界nice_bgm
    【 OpenGauss源码学习 —— 列存储(CU)(二)】
    2023年最全详解:什么是销售管理?销售管理必备百科指南!
    Spring @FeignClient
    lodash库_.chunk、_.pick、_.omit、_.cloneDeep、_.debounce方法
  • 原文地址:https://blog.csdn.net/fzyyyyyyyy/article/details/133713370