[HAOI2010]软件安装

题意

Here

思考

这题的树形 \(dp\) 很明显,我们发现只可能有两种情况,要么是树要么是环,对于一个环来说肯定是要么都选要么都不选,可以缩点,缩完点之后我们得到了一个森林,不妨用一个源点将这些小树串成一个大树再来 \(dp\),后面就显然是一个树上有条件的分组背包了,由于必须要选当前点,所以强制选当前点再 \(dp\) 就好 ~

代码

#include<bits/stdc++.h>
using namespace std;
const int M = 550;
const int N = 110;
struct node{
    int nxt, to;
}edge[N << 1], E[N << 1];
int head[N], num, H[N], num2;
void build(int from, int to){
    edge[++num].nxt = head[from];
    edge[num].to = to;
    head[from] = num;
}
void build2(int from, int to){
    E[++num2].nxt = H[from];
    E[num2].to = to;
    H[from] = num2;
}
int dfn[N], low[N], vis[N], S[N], col[N], sumv[N], sumw[N], val[N], w[N], du[N], top, cnt, color;
void tarjan(int u){
    low[u] = dfn[u] = ++ cnt; S[++top] = u; vis[u] = 1;
    for(int i=head[u]; i; i=edge[i].nxt){
        int v = edge[i].to;
        if(!dfn[v]) tarjan(v), low[u] = min(low[u], low[v]);
        else if(vis[v]) low[u] = min(low[u], dfn[v]);
    }
    if(low[u] == dfn[u]){
        vis[u] = 0; col[u] = ++ color; sumv[color] += val[u]; sumw[color] += w[u];
        while(S[top] != u){
            int v = S[top];
            vis[v] = 0; col[v] = color; sumv[color] += val[v]; sumw[color] += w[v];
            top --;
        }
        top --;
    }
}
int n, m;
int f[N][M], sz[N];
void dp(int u, int fa){
    sz[u] = 1;
    for(int i=sumw[u]; i<=m; i++) f[u][i] = sumv[u];
    for(int i=H[u]; i; i=E[i].nxt){
        int v = E[i].to;
        if(v == fa) continue;
        dp(v, u); sz[u] += sz[v];
        for(int w=m-sumw[u]; w>=0; w--){
            for(int k=0; k<=w; k++){
                f[u][w + sumw[u]] = max(f[u][w + sumw[u]], f[u][w+sumw[u]-k] + f[v][k]);
            }
        }
    }
}
int main(){
    cin >> n >> m;
    for(int i=1; i<=n; i++) cin >> w[i];
    for(int i=1; i<=n; i++) cin >> val[i];
    for(int i=1; i<=n; i++){
        int d; cin >> d; if(d == 0) continue;
        build(d, i);
    }
    for(int i=1; i<=n; i++){
        if(!dfn[i]) tarjan(i);
    }
    for(int u=1; u<=n; u++){
        for(int i=head[u]; i; i=edge[i].nxt){
            int v = edge[i].to;
            if(col[u] == col[v]) continue;
            build2(col[u], col[v]); du[col[v]] ++;
        }
    }
    for(int i=1; i<=color; i++){
        if(du[i] == 0) build2(color + 1, i);
    }
    dp(color+1, 0);
    cout << f[color+1][m];
    return 0;
}

总结

注意细节吧

posted @ 2018-12-09 21:49  alecli  阅读(85)  评论(0编辑  收藏  举报