Bzoj_4316 小C的独立集

题意

给定一个仙人掌,求出这个仙人掌的最大独立点集。

\(n \leqslant 5e4,m \leqslant 6e4\)

题解

哈哈,第一次写仙人掌DP,大脑爆炸。
这里用一种直接DP的方式。设\(f_{x,i,j}\)表示点x的选择情况为i,点x到父亲的那条边所在的环中,深度最大(位于底部)的点的选择情况为j的最大方案。转移嘛,自己想想吧。详见代码。

#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=5e4;
int n,m,tot,ans;
int pre[maxn*4+8],now[maxn+8],son[maxn*4+8];
int fa[maxn+8],color[maxn+8],f[maxn+8][2][2],dep[maxn+8];

int read()
{
    int x=0,f=1;char ch=getchar();
    for (;ch<'0'||ch>'9';ch=getchar()) if (ch=='-') f=-1;
    for (;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
    return x*f;
}

void add(int u,int v)
{
    pre[++tot]=now[u];
    now[u]=tot;
    son[tot]=v;
}

void dfs(int x)
{
    dep[x]=dep[fa[x]]+1;
    for (int p=now[x];p;p=pre[p])
        {
            int child=son[p];
            if (child==fa[x]) continue;
            if (!dep[child])
                {
                    fa[child]=x,dfs(child);
                    for (int i=0;i<2;i++)
                            for (int j=0;j<2;j++)
                                {
                                    int res=0;
                                    for (int k=0;k<2;k++)
                                        for (int l=0;l<2;l++)
                                            {
                                                if (i&k) continue;
                                                if (color[child]!=2&&j!=l) continue;
                                                if (color[child]==1&&k!=l) continue;
                                                if (color[child]==2&&(i&l)) continue;
                                                res=max(res,f[child][k][l]);
                                            }
                                    f[x][i][j]+=res;
                                }
                }   
            else
                if (dep[x]>dep[child])
                    {
                        color[x]=1;
                        int res=x;
                        while(fa[res]!=child) res=fa[res];
                        color[res]=2;
                    }
        }
    f[x][1][0]++,f[x][1][1]++;
    if (color[x]==1)
        {
            f[x][0][1]=f[x][0][0]=max(f[x][0][1],f[x][0][0]);
            f[x][1][1]=f[x][1][0]=max(f[x][1][0],f[x][1][1]);
            f[x][1][0]=f[x][0][1]=0;
        }
}

int main()
{
    n=read(),m=read();
    for (int i=1;i<=m;i++)
        {
            int u=read(),v=read();
            add(u,v),add(v,u);
        }
    for (int i=1;i<=n;i++)
        if (!dep[i])
            {
                dfs(i);
                int res=0;
                for (int j=0;j<2;j++)
                    for (int k=0;k<2;k++)
                        res=max(res,f[i][j][k]);
                ans+=res;
            }
    printf("%d\n",ans);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/Alseo_Roplyer/p/10274363.html