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;
}

猜你喜欢

转载自www.cnblogs.com/shandongs1/p/9458410.html