BZOJ4316 小C的独立集 仙人掌

Posted Mychael

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ4316 小C的独立集 仙人掌相关的知识,希望对你有一定的参考价值。

题目

图论小王子小C经常虐菜,特别是在图论方面,经常把小D虐得很惨很惨。
这不,小C让小D去求一个无向图的最大独立集,通俗地讲就是:在无向图中选出若干个点,这些点互相没有边连接,并使取出的点尽量多。
小D虽然图论很弱,但是也知道无向图最大独立集是npc,但是小C很仁慈的给了一个很有特点的图: 图中任何一条边属于且仅属于一个简单环,图中没有重边和自环。小C说这样就会比较水了。
小D觉得这个题目很有趣,就交给你了,相信你一定可以解出来的。

输入格式

第一行,两个数n, m,表示图的点数和边数。
第二~m+1行,每行两个数x,y,表示x与y之间有一条无向边。

输出格式

输出这个图的最大独立集。

输入样例

5 6

1 2

2 3

3 1

3 4

4 5

3 5

输出样例

2

提示

100% n <=50000, m<=60000

题解

假设这是一棵树,设\(f[i][0]\)表示\(i\)节点为根,不选\(i\)的最大数量,\(f[i][1]\)表示选择\(i\)的最大数量
转移就很简单了,不选\(i\),儿子可以选可以不选,选了\(i\),儿子必须选

如果是仙人掌的话,就先忽略环上的点,然后单独考虑环的影响传递到最高点

#include<iostream>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define LL long long int
#define REP(i,n) for (int i = 1; i <= (n); i++)
#define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
#define BUG(s,n) for (int i = 1; i <= (n); i++) cout<<s[i]<<‘ ‘; puts("");
using namespace std;
const int maxn = 50005,maxm = 120005,INF = 1000000000;
inline int read(){
    int out = 0,flag = 1; char c = getchar();
    while (c < 48 || c > 57) {if (c == ‘-‘) flag = -1; c = getchar();}
    while (c >= 48 && c <= 57) {out = (out << 3) + (out << 1) + c - ‘0‘; c = getchar();}
    return out * flag;
}
int n,m,h[maxn],ne = 2;
struct EDGE{int to,nxt;}ed[maxm];
void build(int u,int v){
    ed[ne] = (EDGE){v,h[u]}; h[u] = ne++;
    ed[ne] = (EDGE){u,h[v]}; h[v] = ne++;
}
int f[maxn][2],fa[maxn],dfn[maxn],low[maxn],cnt;
int c[maxn],ci,g[maxn][2];
void DP(int u,int rt){
    ci = 0; int ans1,ans2;
    for (int i = u; i != rt; i = fa[i]) c[++ci] = i;
    g[u][0] = f[u][0]; g[u][1] = 0;
    for (int i = 2; i <= ci; i++){
        u = c[i];
        if (i == 2) g[u][0] = f[u][0] + g[c[i - 1]][0];
        else g[u][0] = f[u][0] + max(g[c[i - 1]][0],g[c[i - 1]][1]);
        g[u][1] = f[u][1] + g[c[i - 1]][0];
    }
    ans1 = g[c[ci]][0];
    g[c[1]][0] = f[c[1]][0]; g[c[1]][1] = f[c[1]][1];
    for (int i = 2; i <= ci; i++){
        u = c[i];
        g[u][0] = f[u][0] + max(g[c[i - 1]][0],g[c[i - 1]][1]);
        g[u][1] = f[u][1] + g[c[i - 1]][0];
    }
    ans2 = max(g[c[ci]][1],g[c[ci]][0]);
    f[rt][1] += ans1;
    f[rt][0] += ans2;
}
void dfs(int u){
    dfn[u] = low[u] = ++cnt;
    f[u][1] = 1;
    Redge(u) if ((to = ed[k].to) != fa[u]){
        if (!dfn[to]){
            fa[to] = u;
            dfs(to);
            low[u] = min(low[u],low[to]);
        }else low[u] = min(low[u],dfn[to]);
        if (low[to] > dfn[u]){
            f[u][0] += max(f[to][0],f[to][1]);
            f[u][1] += f[to][0];
        }
    }
    Redge(u) if (dfn[to = ed[k].to] > dfn[u] && fa[to] != u)
        DP(to,u);
}
int main(){
    n = read(); m = read();
    while (m--) build(read(),read());
    int ans = 0;
    REP(i,n) if (!dfn[i]){
        dfs(i);
        ans += max(f[i][0],f[i][1]);
    }
    printf("%d\n",ans);
    return 0;
}

以上是关于BZOJ4316 小C的独立集 仙人掌的主要内容,如果未能解决你的问题,请参考以下文章

bzoj4316 小C的独立集

bzoj4316: 小C的独立集

BZOJ4316: 小C的独立集

BZOJ4316 仙人掌DP

BZOJ-1952Area [坑题] 仙人掌DP + 最大点权独立集(改)

BZOJ1487 [HNOI2009]无归岛 仙人掌dp