BZOJ 4316: 小C的独立集 (仙人掌,树形DP)

对于树的情况是简单的.   

我们 DFS 这颗仙人掌,对于树边正常转移就行.  

然后对于环,我们把环拿出来,然后强制讨论端点选/不选再跑一遍 DP 就行.   

code:  

#include <bits/stdc++.h>     
#define N 200006  
#define setIO(s) freopen(s".in","r",stdin) 
using namespace std; 

int n,m,edges,tim; 
int hd[N],to[N],nex[N],dfn[N],low[N],fa[N],f[N][2];  

void add(int u,int v) 
{
    nex[++edges]=hd[u],hd[u]=edges,to[edges]=v; 
}

void calc(int u,int v) 
{
    int f0=0,f1=0;   
    for(int i=v;i!=u;i=fa[i]) 
    {
        int x=f0+f[i][0],y=f1+f[i][1];   
        f0=max(x,y),f1=x;    
    }        
    f[u][0]+=f0;  
    f0=0,f1=-2e9;   
    for(int i=v;i!=u;i=fa[i]) 
    {
        int x=f0+f[i][0],y=f1+f[i][1];   
        f0=max(x,y),f1=x;  
    } 
    f[u][1]+=f1;   
}
void tarjan(int x,int ff) 
{ 
    fa[x]=ff;  
    dfn[x]=low[x]=++tim; 
    f[x][0]=0,f[x][1]=1;    
    for(int i=hd[x];i;i=nex[i]) 
    {
        int v=to[i];  
        if(!dfn[v])    
            tarjan(v,x),low[x]=min(low[x],low[v]);   
        else if(v!=ff) low[x]=min(low[x],dfn[v]);     
        if(low[v]>dfn[x]) 
        {
            f[x][1]+=f[v][0];   
            f[x][0]+=max(f[v][0],f[v][1]); 
        }
    }
    for(int i=hd[x];i;i=nex[i]) 
    {
        int v=to[i]; 
        if(fa[v]!=x&&dfn[x]<dfn[v]) calc(x,v);     
    }
}
int main() 
{ 
    // setIO("input");     
    scanf("%d%d",&n,&m);   
    for(int i=1;i<=m;++i) 
    {
        int u,v;  
        scanf("%d%d",&u,&v);   
        add(u,v),add(v,u); 
    } 
    tarjan(1,0);  
    printf("%d\n",max(f[1][0],f[1][1]));   
    return 0; 
}

  

posted @ 2020-03-29 11:56  EM-LGH  阅读(162)  评论(0编辑  收藏  举报