luogu 2515
对于软件的依赖可以转化为图上点之间的边的关系
发现对于一个强联通分量内的软件,一安则全安
Tarjan缩点
缩点后,从虚拟节点 0 向所有入度为 0 的点连边
这样就构成了一棵树
树形 dp
$dp[i][j]$ 表示对 $i$ 及其子树话费 $j$ 的价格所得到的收益
$dp[i][j] = dp[k][l] + dp[i][j - l]$
#include <bits/stdc++.h> const int N = 110; int head[N], cnt; struct Node {int u, v, nxt;}; int Tim, Bel[N], Low[N], Dfn[N], Stack[N], topp; int W[N], V[N], Tw[N], Tv[N]; Node G[N]; int n, M; bool vis[N]; int Gra; inline void Add(int u, int v) {G[++ cnt].v = v; G[cnt].nxt = head[u]; head[u] = cnt;} void Tarjan(int u) { Dfn[u] = Low[u] = ++ Tim; Stack[++ topp] = u, vis[u] = 1; for(int i = head[u]; ~ i; i = G[i].nxt) { int v = G[i].v; if(!Dfn[v]) { Tarjan(v); Low[u] = std:: min(Low[u], Low[v]); } else if(vis[v]) Low[u] = std:: min(Low[u], Low[v]); } if(Low[u] == Dfn[u]) { vis[u] = 0, Bel[u] = ++ Gra, Tw[Gra] += W[u], Tv[Gra] += V[u]; while(Stack[topp] != u) { vis[Stack[topp]] = 0, Bel[Stack[topp]] = Gra, Tw[Gra] += W[Stack[topp]], Tv[Gra] += V[Stack[topp]]; topp --; } topp --; } } int In[N], head_2[N]; Node E[N]; inline void Add2(int u, int v) {E[++ cnt].v = v, E[cnt].nxt = head_2[u], head_2[u] = cnt;} void Re_build() { cnt = 0; for(int i = 0; i <= Gra; i ++) head_2[i] = -1; for(int u = 1; u <= n; u ++) for(int i = head[u]; ~ i; i = G[i].nxt) { int v = G[i].v; if(Bel[u] != Bel[v]) Add2(Bel[u], Bel[v]), In[Bel[v]] = 1; } } int f[N][N * 5]; void Dfs(int u) { for(int i = head_2[u]; ~ i; i = E[i].nxt) { int v = E[i].v; Dfs(v); for(int j = M - Tw[u]; j >= 0; j --) for(int k = 0; k <= j; k ++) f[u][j] = std:: max(f[u][j], f[u][k] + f[v][j - k]); } for(int j = M; j >= 0; j --) { if(j >= Tw[u]) f[u][j] = f[u][j - Tw[u]] + Tv[u]; else f[u][j] = 0; } } #define gc getchar() inline int read() { int x = 0; char c = gc; while(c < '0' || c > '9') c = gc; while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = gc; return x; } int main() { n = read(), M = read(); for(int i = 1; i <= n; i ++) head[i] = -1; for(int i = 1; i <= n; i ++) W[i] = read(); for(int i = 1; i <= n; i ++) V[i] = read(); for(int i = 1; i <= n; i ++) { int u = read(); if(u) Add(u, i); } for(int i = 1; i <= n; i ++) if(!Dfn[i]) Tarjan(i); Re_build(); for(int i = 1; i <= Gra; i ++) if(!In[i]) Add2(0, i); Dfs(0); std:: cout << f[0][M]; return 0; }