1 条题解

  • 0
    @ 2025-8-24 23:01:08

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar Elaina_0
    今朝依旧,今后亦然。

    搬运于2025-08-24 23:01:08,当前版本为作者最后更新于2024-07-24 10:48:37,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    P10779 BZOJ4316 小 C 的独立集

    感谢管理大大的审核

    虽然在圆方树专题中,但我们没有必要把圆方树建出来...

    AD:博客喵\large 博客喵~

    题意

    给出一个仙人掌图,求最大独立集

    就像是没有上司的舞会超级加倍

    没有做过的可以先去康康~

    分析

    显然树形DP,但是是在仙人掌图上。

    至于啥是仙人掌图嘛~

    感性的李姐一下就是一棵树塞几个基环且强连通。

    引用某dalao的一张图就是:

    由于有环,不难想到 Tarjan,所以我们考虑在 Tarjan 的过程中求解。

    我们设 f[i][1/0]f[i][1/0]ii 节点 /不选选/不选 的最优答案,

    当一条边是树边的时候,正常DP。

    否则暂时不转移。

    当我们做完当前点,发现它是一个环的最顶端的时候,我们需要重新对这个环计算一遍答案。

    从这个环的最底端开始往上跳,每次合并一次答案。

    维护两个变量 f0,f1f0,f1,表示当前点选或者不选的答案。

    考虑分讨:

    • 若最顶端不选

      显然最底端选或者不选是没有影响的。然后正常转移,最后把算出来的 f0f0直接加给顶点。

    • 若顶端选

      那么最底下的那个点就一定不能选,直接令 f1f1 初值为 inf-inf,然后正常转移就好了。

    没了。

    Code

    #include<bits/stdc++.h>
    #define 我永远喜欢 return
    #define 伊蕾娜 0;
    using namespace std;
    #define int long long
    #define rd read()
    #define pii pair<int,int>
    #define mkp make_pair
    #define psb push_back
    inline int read(){
    	int f=1,x=0;
    	char ch=getchar();
    	for(;!isdigit(ch);ch=getchar()) f=(ch=='-'?-1:1);
    	for(;isdigit(ch);ch=getchar()) x=(x<<3)+(x<<1)+ch-'0';
    	return f*x;
    }
    const int N=1e5+100;
    const int inf=0x7fffffff7fffffff;
    
    int n,m,cnt,f[N][2],fa[N];
    vector<int> G[N],T[N*2];
    int dfn[N],low[N],num;
    
    void dp(int x,int y){
    	int g0=0,g1=0,f0=0,f1=0;
    	for(int i=y;i!=x;i=fa[i]){
    		g0=f0+f[i][0],g1=f1+f[i][1];
    		f0=max(g0,g1),f1=g0;
    	}
    	f[x][0]+=f0;
    
    	f0=0,f1=-inf;
    	for(int i=y;i!=x;i=fa[i]){
    		g0=f0+f[i][0],g1=f1+f[i][1];
    		f0=max(g0,g1),f1=g0;
    	}
    	f[x][1]+=f1;
    }
    
    void tarjan(int x,int ff){
    	fa[x]=ff;
    	low[x]=dfn[x]=++num;
    	f[x][1]=1,f[x][0]=0;
    	for(auto to:G[x]){
    		if(!dfn[to]){
    			tarjan(to,x);
    			low[x]=min(low[x],low[to]);
    		}else if(to!=ff){
    			low[x]=min(low[x],dfn[to]);
    		}
    		if(low[to]>dfn[x]){
    			f[x][1]+=f[to][0],f[x][0]+=max(f[to][0],f[to][1]);
    		}
    	}
    	for(auto to:G[x]){
    		if(fa[to]!=x&&dfn[x]<dfn[to]){
    			dp(x,to);
    		}
    	}
    }
    
    signed main(){
    	n=rd,m=rd;
    	for(int i=1;i<=m;i++){
    		int x=rd,y=rd;
    		G[x].psb(y);
    		G[y].psb(x);
    	}
    	tarjan(1,0);
    	printf("%lld",max(f[1][0],f[1][1]));
    	我永远喜欢 伊蕾娜
    }
    
    • 1

    信息

    ID
    10545
    时间
    1000ms
    内存
    512MiB
    难度
    6
    标签
    递交数
    0
    已通过
    0
    上传者