视频链接:
参考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); //DPprintf("%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); //DPprintf("%d\n",f[0][m]); }