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]);
}
复制代码

 

posted @   董晓  阅读(66)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示