E96 Tarjan缩点+树上背包 P2515 [HAOI2010] 软件安装
视频链接:E96 Tarjan缩点+树上背包 P2515 [HAOI2010] 软件安装_哔哩哔哩_bilibili
参考1:D14【模板】强连通分量 Tarjan 算法 - 董晓 - 博客园
参考2:E76 树上背包 P1064 [NOIP2006 提高组] 金明的预算方案 - 董晓 - 博客园
P2515 [HAOI2010] 软件安装 - 洛谷 | 计算机科学教育新生态
// Tarjan缩点+树上背包 O(n*m) #include <iostream> #include <cstdlib> #include <cstdio> #include <algorithm> using namespace std; const int N=505; struct E{int y,ne;}e[N<<1]; int head[N],idx; void add(int x,int y){ e[++idx]={y,head[x]};head[x]=idx; } int n,m,w[N],v[N],d[N]; int dfn[N],low[N],tim,scc[N],cnt,stk[N],top; int W[N],V[N],ind[N],f[N][N]; void tarjan(int x){ dfn[x]=low[x]=++tim;stk[++top]=x; for(int i=head[x];i;i=e[i].ne){ int y=e[i].y; if(!dfn[y]){ //若y未访问 tarjan(y); low[x]=min(low[x],low[y]); } else if(!scc[y]) //若y已访问且未处理 low[x]=min(low[x],dfn[y]); } if(dfn[x]==low[x]){ ++cnt; while(1){ int y=stk[top--]; scc[y]=cnt; W[cnt]+=w[y]; V[cnt]+=v[y]; if(y==x) break; } } } void dfs(int x){ for(int i=head[x];i;i=e[i].ne){ int y=e[i].y; for(int j=0;j<=m-W[y];j++) f[y][j]=f[x][j]+V[y]; dfs(y); for(int j=W[y];j<=m;j++) f[x][j]=max(f[x][j],f[y][j-W[y]]); } } int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%d",&w[i]); for(int i=1;i<=n;i++) scanf("%d",&v[i]); for(int i=1;i<=n;i++){ scanf("%d",&d[i]); if(d[i])add(d[i],i); } for(int i=1;i<=n;i++) //缩点 if(!dfn[i]) tarjan(i); for(int i=1;i<=n;i++) head[i]=0;idx=0; for(int i=1;i<=n;i++) //连边 if(scc[d[i]]!=scc[i]) add(scc[d[i]],scc[i]),ind[scc[i]]++; for(int i=1;i<=cnt;i++) //变成树 if(!ind[i]) add(0,i); dfs(0); //DP printf("%d\n",f[0][m]); }
// Tarjan缩点+树上背包 未优化 O(n*m*m) #include <iostream> #include <cstdlib> #include <cstdio> #include <algorithm> using namespace std; const int N=505; struct E{int y,ne;}e[N<<1]; int head[N],idx; void add(int x,int y){ e[++idx]={y,head[x]};head[x]=idx; } int n,m,w[N],v[N],d[N]; int dfn[N],low[N],tim,scc[N],cnt,stk[N],top; int W[N],V[N],ind[N],f[N][N]; void tarjan(int x){ dfn[x]=low[x]=++tim;stk[++top]=x; for(int i=head[x];i;i=e[i].ne){ int y=e[i].y; if(!dfn[y]){ //若y未访问 tarjan(y); low[x]=min(low[x],low[y]); } else if(!scc[y]) //若y已访问且未处理 low[x]=min(low[x],dfn[y]); } if(dfn[x]==low[x]){ ++cnt; while(1){ int y=stk[top--]; scc[y]=cnt; W[cnt]+=w[y]; V[cnt]+=v[y]; if(y==x) break; } } } void dfs(int x){ for(int i=W[x];i<=m;i++)f[x][i]=V[x]; for(int i=head[x];i;i=e[i].ne){ int y=e[i].y; dfs(y); for(int j=m;j>=W[x];j--) //体积 for(int k=0;k<=j-W[x];k++) //决策 f[x][j]=max(f[x][j],f[x][j-k]+f[y][k]); } } int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%d",&w[i]); for(int i=1;i<=n;i++) scanf("%d",&v[i]); for(int i=1;i<=n;i++){ scanf("%d",&d[i]); if(d[i])add(d[i],i); } for(int i=1;i<=n;i++) //缩点 if(!dfn[i]) tarjan(i); for(int i=1;i<=n;i++) head[i]=0;idx=0; for(int i=1;i<=n;i++) //连边 if(scc[d[i]]!=scc[i]) add(scc[d[i]],scc[i]),ind[scc[i]]++; for(int i=1;i<=cnt;i++) //变成树 if(!ind[i]) add(0,i); dfs(0); //DP printf("%d\n",f[0][m]); }
分类:
E 动态规划
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!