BZOJphp
考慮樹的獨立集求法
設\(f[i][0/1]\)表示\(i\)這個點必定不選,以及\(i\)這個點無所謂的最大值
轉移\(f[u][0]=\sum f[v][1]\),\(f[u][1]=\sum f[v][0]\),\(f[u][1]=max(f[u][1],f[u][0])\)
如今放在了仙人掌上,
咱們能夠看作一棵樹加上了若干不相交的返祖邊
因而再加上一維\(f[u][0/1][0/1]\)
其中最後一維表示這條邊所在的環的最底端的那個點必定不選,或者無所謂
賦初值:\(f[u][1][1]=1\),若是這個點不是所在環的最底端,\(f[u][1][0]=1\)
此時的轉移:
1.兩個點的底端點相同
這個時候咱們先只考慮強制不選底端的轉移
那麼,\(f[u][1][0]+=f[v][1][1],f[u][1][1]+=f[v][1][0]\)
也就是上面裸的在樹上的轉移ios
2.兩個點的底端點不一樣
既然跨越了環,意味着\(u\)就是這個環的底端點,\(v\)是它所在環的頂端點
那麼,能夠\(u\)選\(v\)不選,由於跨越了環,因此對於\(v\)的底端點選擇與否咱們是不關心的
而第二維的\(1\)表示的\(u\)無所謂,後面的\(0\)則是強制不選擇\(u\)
所以\(f[u][0][0]+=f[v][1][1]\),\(f[u][1][0]+=f[v][0][0]\)spa
3.\(v\)的頂端點不是\(u\)
意味着不用擔憂底端點產生的影響
因此\(f[u][0][1]+=f[v][1][1]\),\(f[u][1][1]+=f[v][0][1]\)code
4.\(v\)的頂端點是\(u\)
此時要考慮底端點的貢獻了
此時當前\(u\)不選,那就沒有什麼問題\(f[u][0][1]+=f[v][1][1]\)
當前\(u\)選擇,強制不能選擇底端點\(f[u][1][1]+=f[v][0][0]\)get
好了,這樣就討論完了四種轉移,而後就能夠啦string
#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<cmath> #include<algorithm> #include<set> #include<map> #include<vector> #include<queue> using namespace std; #define ll long long #define RG register #define MAX 55555 inline int read() { RG int x=0,t=1;RG char ch=getchar(); while((ch<'0'||ch>'9')&&ch!='-')ch=getchar(); if(ch=='-')t=-1,ch=getchar(); while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar(); return x*t; } struct Line{int v,next;}e[MAX*3]; int h[MAX],cnt=1,n,m; inline void Add(int u,int v){e[cnt]=(Line){v,h[u]};h[u]=cnt++;} int dep[MAX],fa[MAX]; int tp[MAX],un[MAX]; void dfs(int u,int ff) { fa[u]=ff;dep[u]=dep[ff]+1; for(int i=h[u];i;i=e[i].next) if(!dep[e[i].v])dfs(e[i].v,u); } void jump(int u,int v){int x=v;while(x!=u)tp[x]=u,un[x]=v,x=fa[x];} int f0[MAX],f1[MAX],g0[MAX],g1[MAX]; void dp(int u) { f1[u]=1; if(u!=un[u])g1[u]=1; for(int i=h[u];i;i=e[i].next) { int v=e[i].v;if(dep[u]+1!=dep[v])continue; dp(v); if(un[u]!=un[v])g0[u]+=f1[v],g1[u]+=g0[v]; else g0[u]+=g1[v],g1[u]+=g0[v]; if(tp[v]!=u)f0[u]+=f1[v],f1[u]+=f0[v]; else f0[u]+=f1[v],f1[u]+=g0[v]; } f1[u]=max(f1[u],f0[u]); g1[u]=max(g1[u],g0[u]); } int main() { n=read();m=read(); for(int i=1;i<=m;++i) { int u=read(),v=read(); Add(u,v);Add(v,u); } dfs(1,0); for(int u=1;u<=n;++u) for(int i=h[u];i;i=e[i].next) if(dep[u]<dep[e[i].v]&&fa[e[i].v]!=u) jump(u,e[i].v); dp(1); printf("%d\n",f1[1]); return 0; }