zoukankan      html  css  js  c++  java
  • 【题解】Bzoj4316小C的独立集

      决定要开始学习圆方树 & 仙人掌相关姿势。加油~~

      其实感觉仙人掌本质上还是一棵树,长得也还挺优美的。很多的想法都可以往树的方面上靠,再针对仙人掌的特性做出改进。这题首先如果是在树上的话那么实际上就是没有上司的舞会。当出现了环的时候意味着我们需要针对环的存在做出特殊的处理。

      还是设立状态 (f[i][1/0]) 表示在 (i) 的子树内(包括(i))时选取 (i) 与不选取 (i) 的最大独立集大小。当转移发生在树边上的时候,直接转移。当不是树边的时候,我们可以将环上的点单独拿出来重新dp。实际上也就是要处理环上非树边的排斥关系,保证这层关系并转移。其实由于仙人掌上的环不包含,不交叉,很多的时候是类似于一棵基环树的(只不过环变多了?但不影响本质吧)。

      判断树边/非树边的依据就是 (dfn, low) 等值的大小。而一个环的根与底部也同样可以运用dfs树的性质来解决。

    #include <bits/stdc++.h>
    using namespace std;
    #define maxn 150000
    #define INF 99999999 
    int n, m, cnp = 1, head[maxn];
    int f[maxn][2], fa[maxn];
    int timer, dfn[maxn], low[maxn];
    
    struct edge
    {
        int to, last;
    }E[maxn];
    
    int read()
    {
        int x = 0, k = 1;
        char c;
        c = getchar();
        while(c < '0' || c > '9') { if(c == '-') k = -1; c = getchar(); }
        while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
        return x * k;
    }
    
    void add(int u, int v)
    {
        E[cnp].to = v, E[cnp].last = head[u], head[u] = cnp ++;
        E[cnp].to = u, E[cnp].last = head[v], head[v] = cnp ++;
    }
    
    void DP(int S, int T)
    {
        int f1 = 0, f0 = 0;
        for(int i = T; i != S; i = fa[i])
        {
            int t1 = f1 + f[i][1], t0 = f0 + f[i][0];
            f0 = max(t1, t0); f1 = t0; 
        }
        f[S][0] += f0; f0 = 0, f1 = -INF;
        for(int i = T; i != S; i = fa[i])
        {
            int t1 = f1 + f[i][1], t0 = f0 + f[i][0];
            f0 = max(t1, t0); f1 = t0; 
        }
        f[S][1] += f1;
    }
    
    void dfs(int u, int gra)
    {
        fa[u] = gra; dfn[u] = low[u] = ++ timer;
        f[u][1] = 1, f[u][0] = 0;
        for(int i = head[u]; i; i = E[i].last)
        {
            int v = E[i].to;
            if(!dfn[v]) dfs(v, u), low[u] = min(low[u], low[v]);
            else if(v != gra) low[u] = min(low[u], dfn[v]);
            if(low[v] > dfn[u]) 
                f[u][1] += f[v][0], f[u][0] += max(f[v][0], f[v][1]);
        }
        for(int i = head[u]; i; i = E[i].last)
            if(fa[E[i].to] != u && dfn[u] < dfn[E[i].to])
                DP(u, E[i].to);
    }
    
    int main()
    {
        n = read(), m = read();
        for(int i = 1; i <= m; i ++)
        {
            int u = read(), v = read();
            add(u, v);
        }
        dfs(1, 0);
        printf("%d
    ", max(f[1][0], f[1][1]));
        return 0;
    }
  • 相关阅读:
    题目1101:计算表达式
    九度oj 题目1107:搬水果
    [Hihocoder] 字符串排序
    [hzwer] 模拟T
    [Luogu] 宝藏
    [Luogu] 列队
    [Luogu] 奶酪
    [Luogu] 逛公园
    [Luogu] 时间复杂度
    [Luogu] 小凯的疑惑
  • 原文地址:https://www.cnblogs.com/twilight-sx/p/9206435.html
Copyright © 2011-2022 走看看