【BZOJ4316】小C的獨立集(仙人掌,動態規劃)

【BZOJ4316】小C的獨立集(仙人掌,動態規劃)

題面

BZOJphp

題解

除了普通的動態規劃之外,這題還能夠用仙人掌的作法來作。
這裏沒有必要把圓方樹給創建出來
\(Tarjan\)的本質其實就是一個構建\(dfs\)樹的過程
因此咱們在\(Tarjan\)的過程當中求解就好了
咱們設\(f[i][0/1]\)表示當前節點爲\(i\),選或不選的子樹的最大獨立集
當一條邊是樹邊的時候,轉移和樹上的轉移相同。
不然暫時不轉移。
當咱們作完當前點,發現它是一個環的最頂端的時候,咱們須要從新對於這個環計算一遍答案。
咱們須要明白一點:對於環上的節點,只與環有關,掛在環外面的子樹能夠直接計算在一塊兒。ios

如今考慮對於環如何從新計算答案
從這個環的最底端開始往上跳,每次合併一次答案
先考慮如何計算最頂端不選
這樣子最底端選或者不選是沒有關係的。
維護兩個變量\(f_0,f_1\),表示當前點選或者不選的答案
向上轉移和樹上的轉移就是同樣的了。
把算出來的\(f_0\)直接加給頂點
而後計算頂端選,
那麼最底下的那個點就必定不能選,直接令\(f_1\)初值爲\(-\infty\)就行了spa

這樣子作完就至關於把環給單獨拎出來考慮,
而後就變成了樹上的\(dp\)code

#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;
int n,m,fa[MAX],f[MAX][2],dfn[MAX],low[MAX],tim;
inline void Add(int u,int v){e[cnt]=(Line){v,h[u]};h[u]=cnt++;}
void dp(int u,int y)
{
    int t0,t1,f0=0,f1=0;
    for(int i=y;i!=u;i=fa[i])
    {
        t0=f0+f[i][0];t1=f1+f[i][1];
        f0=max(t0,t1);f1=t0;
    }
    f[u][0]+=f0;
    f0=0;f1=-1e9;
    for(int i=y;i!=u;i=fa[i])
    {
        t0=f0+f[i][0];t1=f1+f[i][1];
        f0=max(t0,t1);f1=t0;
    }
    f[u][1]+=f1;
}
void dfs(int u,int ff)
{
    fa[u]=ff;dfn[u]=low[u]=++tim;
    f[u][1]=1;f[u][0]=0;
    for(int i=h[u];i;i=e[i].next)
    {
        int v=e[i].v;
        if(!dfn[v])dfs(v,u),low[u]=min(low[u],low[v]);
        else if(v!=ff)low[u]=min(low[u],dfn[v]);
        if(low[v]>dfn[u])
            f[u][1]+=f[v][0],f[u][0]+=max(f[v][0],f[v][1]);
    }
    for(int i=h[u];i;i=e[i].next)
        if(fa[e[i].v]!=u&&dfn[u]<dfn[e[i].v])
            dp(u,e[i].v);
}
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);
    printf("%d\n",max(f[1][0],f[1][1]));
    return 0;
}
相關文章
相關標籤/搜索