• bzoj4316: 小C的独立集


    Description

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

    Input

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

    Output

    输出这个图的最大独立集。
     
    dfs一次断开每个环上最后被访问到的一条边,环上除了环的根以外所有点组成一条链
    f0/f1表示一个点不选/不做强制要求时dfs子树内的最大独立集
    g0/g1表示一个点不选/不做强制要求,但这个点所在的链的底部强制不选时dfs子树内的最大独立集
    转移方式类似树形dp
    #include<cstdio>
    const int N=51000,R=1500000;
    char buf[R+4],*ptr=buf-1;
    int n,m,ans=0;
    int et[121000],enx[121000],e0[N],ep=2;
    int ed[N],stk[N],stp=0,bm[N],tp[N],dep[N];
    int f0[N],f1[N],g0[N],g1[N];
    inline int _int(){
        int x=0,c=*++ptr;
        while(c<48)c=*++ptr;
        while(c>47)x=x*10+c-48,c=*++ptr;
        return x;
    }
    inline void maxs(int&a,int b){if(a<b)a=b;}
    bool rt[N];
    void dfs1(int w){
        ed[w]=1;
        stk[++stp]=w;
        for(int i=e0[w],u;i;i=enx[i])if(u=et[i]){
            if(!ed[u]){
                et[i^1]=0;
                dep[u]=dep[w]+1;
                dfs1(u);
            }else{
                et[i]=et[i^1]=0;
                while(dep[stk[stp]]>dep[u]){
                    int x=stk[stp--];
                    bm[x]=w;tp[x]=u;
                }
            }
        }
        if(stk[stp]==w)--stp;
    }
    void dfs2(int w){
        f1[w]=1;
        if(w!=bm[w])g1[w]=1;
        for(int i=e0[w],u;i;i=enx[i])if(u=et[i]){
            dfs2(u);
            if(bm[u]!=bm[w]){
                if(tp[u]!=w)g0[w]+=f1[u],g1[w]+=f0[u];
                else g0[w]+=f1[u],g1[w]+=g0[u];
            }else g0[w]+=g1[u],g1[w]+=g0[u];
            if(tp[u]!=w)f0[w]+=f1[u],f1[w]+=f0[u];
            else f0[w]+=f1[u],f1[w]+=g0[u];
        }
        maxs(f1[w],f0[w]);
        maxs(g1[w],g0[w]);
    }
    int main(){
        fread(buf,1,R,stdin);
        n=_int();m=_int();
        while(m--){
            int a=_int(),b=_int();
            et[ep]=b;enx[ep]=e0[a];e0[a]=ep++;
            et[ep]=a;enx[ep]=e0[b];e0[b]=ep++;
        }
        dfs1(1);dfs2(1);
        printf("%d
    ",f1[1]);
        return 0;
    }
  • 相关阅读:
    面试题15 链表中倒数第k个结点
    面试题14 调整数组顺序使奇数位于偶数前面
    面试题13 在O(1)时间删除链表结点
    面试题12 打印1到最大的N位数
    面试题11 数值的整数次方
    面试题10 二进制中1的个数
    面试题9 斐波那契数列
    面试题8 旋转数组的最小数字
    关于神经网络训练的一些建议笔记
    两篇将rf和boosting方法用在搜索排序上的paper
  • 原文地址:https://www.cnblogs.com/ccz181078/p/5646777.html
Copyright © 2020-2023  润新知