【题解】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\n", max(f[1][0], f[1][1]));
    return 0;
}

 

posted @ 2018-06-20 22:27  Twilight_Sx  阅读(246)  评论(0编辑  收藏  举报