Description
图论小王子小C经常虐菜,特别是在图论方面,经常把小D虐得很惨很惨。
这不,小C让小D去求一个无向图的最大独立集,通俗地讲就是:在无向图中选出若干个点,这些点互相没有边连接,并使取出的点尽量多。
小D虽然图论很弱,但是也知道无向图最大独立集是npc,但是小C很仁慈的给了一个很有特点的图: 图中任何一条边属于且仅属于一个简单环,图中没有重边和自环。小C说这样就会比较水了。
小D觉得这个题目很有趣,就交给你了,相信你一定可以解出来的。
Input
第一行,两个数n, m,表示图的点数和边数。
第二~m+1行,每行两个数x,y,表示x与y之间有一条无向边。
Output
输出这个图的最大独立集。
dfs一次断开每个环上最后被访问到的一条边,环上除了环的根以外所有点组成一条链
f0/f1表示一个点不选/不做强制要求时dfs子树内的最大独立集
g0/g1表示一个点不选/不做强制要求,但这个点所在的链的底部强制不选时dfs子树内的最大独立集
转移方式类似树形dp
#include<cstdio> const int N=51000,R=1500000; char buf[R+4],*ptr=buf-1; int n,m,ans=0; int et[121000],enx[121000],e0[N],ep=2; int ed[N],stk[N],stp=0,bm[N],tp[N],dep[N]; int f0[N],f1[N],g0[N],g1[N]; inline int _int(){ int x=0,c=*++ptr; while(c<48)c=*++ptr; while(c>47)x=x*10+c-48,c=*++ptr; return x; } inline void maxs(int&a,int b){if(a<b)a=b;} bool rt[N]; void dfs1(int w){ ed[w]=1; stk[++stp]=w; for(int i=e0[w],u;i;i=enx[i])if(u=et[i]){ if(!ed[u]){ et[i^1]=0; dep[u]=dep[w]+1; dfs1(u); }else{ et[i]=et[i^1]=0; while(dep[stk[stp]]>dep[u]){ int x=stk[stp--]; bm[x]=w;tp[x]=u; } } } if(stk[stp]==w)--stp; } void dfs2(int w){ f1[w]=1; if(w!=bm[w])g1[w]=1; for(int i=e0[w],u;i;i=enx[i])if(u=et[i]){ dfs2(u); if(bm[u]!=bm[w]){ if(tp[u]!=w)g0[w]+=f1[u],g1[w]+=f0[u]; else g0[w]+=f1[u],g1[w]+=g0[u]; }else g0[w]+=g1[u],g1[w]+=g0[u]; if(tp[u]!=w)f0[w]+=f1[u],f1[w]+=f0[u]; else f0[w]+=f1[u],f1[w]+=g0[u]; } maxs(f1[w],f0[w]); maxs(g1[w],g0[w]); } int main(){ fread(buf,1,R,stdin); n=_int();m=_int(); while(m--){ int a=_int(),b=_int(); et[ep]=b;enx[ep]=e0[a];e0[a]=ep++; et[ep]=a;enx[ep]=e0[b];e0[b]=ep++; } dfs1(1);dfs2(1); printf("%d\n",f1[1]); return 0; }