bzoj 4316: 小C的独立集 — 圆方树,dp

 

4316: 小C的独立集

Time Limit: 10 Sec  Memory Limit: 128 MB

Description

图论小王子小C经常虐菜,特别是在图论方面,经常把小D虐得很惨很惨。
这不,小C让小D去求一个无向图的最大独立集,通俗地讲就是:在无向图中选出若干个点,这些点互相没有边连接,并使取出的点尽量多。
小D虽然图论很弱,但是也知道无向图最大独立集是npc,但是小C很仁慈的给了一个很有特点的图: 图中任何一条边属于且仅属于一个简单环,图中没有重边和自环。小C说这样就会比较水了。
小D觉得这个题目很有趣,就交给你了,相信你一定可以解出来的。

Input

第一行,两个数n, m,表示图的点数和边数。
第二~m+1行,每行两个数x,y,表示x与y之间有一条无向边。

Output

输出这个图的最大独立集。

Sample Input

5 6
1 2
2 3
3 1
3 4
4 5
3 5

Sample Output

2

HINT

100% n <=50000, m<=60000

Source

emmm直接搞出圆方树然后dp
我们只需要对于方点特殊处理
因为我们发现对于方点向上的更新,如果fa[x]取的话他会由f[x][0]更新,所以f[x][0]实际表示的是x儿子中头尾两个点不取的最优代价,我们可以再dp一下得到
同理,对于f[x][1]表示儿子中不相邻取法的最优代价,一样可以dp求得
#include<map>
#include<cmath>
#include<queue>
#include<cstdio>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define inf 1000000007
#define ll long long
#define N 120010
inline int rd()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
int n,m,nn;
int dfn[N],tim,fa[N],len[N];
bool vs[N];
struct cst
{
    int lj[N],fro[N],to[N],cnt=0;
    void add(int a,int b){fro[++cnt]=lj[a];to[cnt]=b;lj[a]=cnt;}
    int f[N][2],s[N],sz;
    int g[N][2];//表示第i个儿子选或者不选的最大个数
    void sol(int x)
    {
        sz=0;
        for(int i=lj[x];i;i=fro[i]) s[++sz]=to[i];
        if(sz==2)
        {
            f[x][0]=f[s[1]][0]+f[s[2]][0];
            f[x][1]=max(f[s[1]][0]+f[s[2]][0],max(f[s[1]][0]+f[s[2]][1],f[s[1]][1]+f[s[2]][0]));
            return;
        }
        g[1][0]=f[s[1]][0];g[1][1]=-inf;
        for(int i=2;i<=sz;i++)
        {
            g[i][1]=g[i-1][0]+f[s[i]][1];
            g[i][0]=max(g[i-1][1],g[i-1][0])+f[s[i]][0];
        }
        f[x][0]=g[sz][0];
        g[1][0]=f[s[1]][0];g[1][1]=f[s[1]][1];
        for(int i=2;i<=sz;i++)
        {
            g[i][1]=g[i-1][0]+f[s[i]][1];
            g[i][0]=max(g[i-1][1],g[i-1][0])+f[s[i]][0];
        }
        f[x][1]=max(g[sz][0],g[sz][1]);
    }
    void dfs(int x)
    {
        f[x][0]=0;
        f[x][1]=(x<=nn);
        for(int i=lj[x];i;i=fro[i])
        {
            dfs(to[i]);
            if(x<=nn)
            {
                f[x][0]+=max(f[to[i]][0],f[to[i]][1]);
                f[x][1]+=f[to[i]][0];
            }
        }
        if(x>nn) sol(x);
    }
    void work()
    {
        dfs(1);
        printf("%d\n",max(f[1][0],f[1][1]));
    }
}T;

int lj[N],fro[N],to[N],cnt;
void add(int a,int b){fro[++cnt]=lj[a];to[cnt]=b;lj[a]=cnt;}

void tarjan(int x)
{
    dfn[x]=++tim;
    for(int i=lj[x],tx;i;i=fro[i])
    {
        if(to[i]==fa[x]) continue;
        if(!dfn[to[i]]) fa[to[i]]=x,tarjan(to[i]);
        else if(dfn[to[i]]<dfn[x])
        {
            len[++n]=dfn[x]-dfn[to[i]]+1;
            fa[n]=to[i];
            T.add(to[i],n);
            tx=x;
            while(tx^to[i])
            {
                T.add(n,tx);
                vs[tx]=1;
                tx=fa[tx];
            }
        }
    }
    if(!vs[x]) T.add(fa[x],x);
    tim--;
}
int main()
{
    nn=n=rd();m=rd();
    for(int i=1,x,y;i<=m;i++)
    {
        x=rd();y=rd();
        add(x,y);add(y,x);
    }
    tarjan(1);
    T.work();
    return 0;
}

 

评论

还没有任何评论,你来说两句吧

发表评论

衫小寨 出品