zoukankan      html  css  js  c++  java
  • 【BZOJ】4316: 小C的独立集 静态仙人掌

    【题意】给定仙人掌图,求最大独立集(选择最大的点集使得点间无连边)。n<=50000,m<=60000。

    【算法】DFS处理仙人掌图

    【题解】参考:【BZOJ】1023: [SHOI2008]cactus仙人掌图

    对仙人掌进行无向图的点双连通分量Tarjan算法,树边正常DP,环边(low[y]<=dfn[x])无视。

    每个环在其深度最小的点整体处理(找到(u,v)只须fa[v]≠u&&dfn[y]>dfn[x])。

    DP的做法参考:【BZOJ】1040: [ZJOI2008]骑士 环套树DP

    #include<cstdio>
    #include<cctype>
    #include<algorithm>
    using namespace std;
    int read(){
        char c;int s=0,t=1;
        while(!isdigit(c=getchar()))if(c=='-')t=-1;
        do{s=s*10+c-'0';}while(isdigit(c=getchar()));
        return s*t;
    }
    const int maxn=100010;
    struct edge{int v,from;}e[maxn*2];
    int n,m,tot,first[maxn],fa[maxn],f[maxn][2],g[maxn][2];
    int dfn[maxn],low[maxn],dfsnum=0;
    void insert(int u,int v){tot++;e[tot].v=v;e[tot].from=first[u];first[u]=tot;}
    
    void solve(int u,int v){
        int cnt=0;
        for(int i=v;i!=fa[u];i=fa[i]){cnt++;g[cnt][0]=f[i][0];g[cnt][1]=f[i][1];}
        for(int i=2;i<=cnt;i++){
            g[i][0]+=max(g[i-1][0],g[i-1][1]);
            g[i][1]+=g[i-1][0];
        }
        f[u][0]=g[cnt][0];
        cnt=0;
        for(int i=v;i!=fa[u];i=fa[i]){cnt++;g[cnt][0]=f[i][0];g[cnt][1]=f[i][1];}
        g[1][1]=-0x3f3f3f3f;
        for(int i=2;i<=cnt;i++){
            g[i][0]+=max(g[i-1][0],g[i-1][1]);
            g[i][1]+=g[i-1][0];
        }
        f[u][1]=g[cnt][1];
    }    
    void tarjan(int x,int father){
        dfn[x]=low[x]=++dfsnum;f[x][0]=0;f[x][1]=1;
        for(int i=first[x];i;i=e[i].from)if(i!=father){
            int y=e[i].v;
            if(!dfn[y]){
                fa[y]=x;
                tarjan(y,i);
                low[x]=min(low[x],low[y]);
            }else low[x]=min(low[x],dfn[y]);
            if(low[y]>dfn[x]){
                f[x][0]+=max(f[y][0],f[y][1]);
                f[x][1]+=f[y][0];
            }
        }
        for(int i=first[x];i;i=e[i].from)if(fa[e[i].v]!=x&&dfn[e[i].v]>dfn[x])solve(x,e[i].v);
    }
    int main(){
        n=read();m=read();
        for(int i=1;i<=m;i++){
            int u=read(),v=read();
            insert(u,v);insert(v,u);
        }
        tarjan(1,0);
        printf("%d",max(f[1][0],f[1][1]));
        return 0;
    }
    View Code
  • 相关阅读:
    利用Github Actions自动保持 GitHub 提交状态常绿
    windows下搭建轻量级php代码审计环境
    jquery实现点击弹出对话框
    redis学习记录(1)Redis简介
    StatefulSet
    Pod
    Spark 写Hive指定动态分区
    我常用的git操作
    在C#中如何使用GetOpenFileName函数多选文件
    image matching challenge
  • 原文地址:https://www.cnblogs.com/onioncyc/p/8312843.html
Copyright © 2011-2022 走看看