4316: 小C的独立集

Description

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

Input

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

Output

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

Sample Input

5 6
1 2
2 3
3 1
3 4
4 5
3 5

Sample Output

2
题解:
由题目可得,这是一颗仙人掌树。
求最大独立集的话,如果是无环的,f[i]表示选i这个点的最大独立集,g[i]表示不选i这个点的最大独立集。
易得:
f[i]= ∑(g[son]+val[x])
g[i]= ∑max(f[son],g[son])
然后先做没有环的,在做环形DP,这题跟bzoj1487很像(环形DP),所以详见bzoj1487:
或者看代码也行。
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;
const int N=50010;
struct node{
	int y,next;
}sa[120010];int first[N],len=0;
int n,m;
void ins(int x,int y)
{
	len++;
	sa[len].y=y;
	sa[len].next=first[x];
	first[x]=len;
}
int dfn[N],low[N],dep[N],fa[N],f[N],g[N],cnt=0;
//f[i]表示选i,g[i]表示不选 i
void dp(int rt,int x)
{
	int u1=0,u0=0,v1,v0;//u1表示可以取,u0不可以取,v1取了后的值,v0没取的值
    for(int i=x;i!=rt;i=fa[i])
    {
        v1=u1+f[i];v0=u0+g[i];
        u1=v0;u0=max(v1,v0);
     } 
     //因为x取了,所以root不能取 
     g[rt]+=u0;
     u1=-99999999,u0=0;
    for(int i=x;i!=rt;i=fa[i])
    {
        v1=u1+f[i];v0=u0+g[i];
        u1=v0;u0=max(v1,v0);
     } 
     //因为u1太小,所以x没有取 
     f[rt]+=u1;
}
void dfs(int x)
{
	cnt++;
	dfn[x]=low[x]=cnt;
	f[x]=1;
	for(int i=first[x];i!=-1;i=sa[i].next)
	{
		int y=sa[i].y;
		if(y!=fa[x])
		{
			if(!dfn[y])
			{
				fa[y]=x;
				dep[y]=dep[x]+1;
				dfs(y);
				low[x]=min(low[x],low[y]);
			}
			else low[x]=min(low[x],dfn[y]);
		}
		if(low[y]>dfn[x])
		{
			f[x]+=g[y];
			g[x]+=max(g[y],f[y]);
		}
	}
	for(int i=first[x];i!=-1;i=sa[i].next)
	{
		int y=sa[i].y;
	if(fa[y]!=x&&dfn[x]<dfn[y])
	dp(x,y);
	}
	
}
int main()
{
	memset(first,-1,sizeof(first));
	scanf("%d%d",&n,&m);
	int a,b;
	for(int i=1;i<=m;i++)
	{
		scanf("%d%d",&a,&b);
		ins(a,b);ins(b,a);
	}
	dfs(1);
	printf("%d\n",max(f[1],g[1]));
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值