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;
}

posted @ 2018-01-28 19:15  Mychael  阅读(271)  评论(0编辑  收藏  举报