zoukankan      html  css  js  c++  java
  • 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
    ",ans);
    	return 0;
    }
    
    
  • 相关阅读:
    [洛谷P3369] 普通平衡树 Treap & Splay
    [NOIp2016] 组合数问题
    [洛谷P4777] [模板] 扩展中国剩余定理
    [洛谷P3384] [模板] 树链剖分
    [NOIp2017] 时间复杂度
    [bzoj3270] 博物馆
    [USACO06DEC] Milk Patterns
    [USACO5.1] Musical Themes
    后缀数组 模板+详解
    [HNOI2004] L语言
  • 原文地址:https://www.cnblogs.com/Mychael/p/8372135.html
Copyright © 2011-2022 走看看