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:
http://blog.csdn.net/cx_lzx/article/details/76976016
或者看代码也行。
#include
#include
#include
#include
#include
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]


你可能感兴趣的:(DP,仙人掌)