1 条题解
-
0
自动搬运
来自洛谷,原作者为

Elaina_0
今朝依旧,今后亦然。搬运于
2025-08-24 23:01:08,当前版本为作者最后更新于2024-07-24 10:48:37,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
P10779 BZOJ4316 小 C 的独立集
感谢管理大大的审核
虽然在圆方树专题中,但我们没有必要把圆方树建出来...
AD:~
题意
给出一个仙人掌图,求最大独立集
就像是没有上司的舞会超级加倍
没有做过的可以先去康康~
分析
显然树形DP,但是是在仙人掌图上。
至于啥是仙人掌图嘛~
感性的李姐一下就是一棵树塞几个基环且强连通。
引用某dalao的一张图就是:

由于有环,不难想到 Tarjan,所以我们考虑在 Tarjan 的过程中求解。
我们设 为 节点 的最优答案,
当一条边是树边的时候,正常DP。
否则暂时不转移。
当我们做完当前点,发现它是一个环的最顶端的时候,我们需要重新对这个环计算一遍答案。
从这个环的最底端开始往上跳,每次合并一次答案。
维护两个变量 ,表示当前点选或者不选的答案。
考虑分讨:
-
若最顶端不选
显然最底端选或者不选是没有影响的。然后正常转移,最后把算出来的 直接加给顶点。
-
若顶端选
那么最底下的那个点就一定不能选,直接令 初值为 ,然后正常转移就好了。
没了。
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
- 上传者