某岛

… : "…アッカリ~ン . .. . " .. .
September 19, 2021

树形背包

暴力枚举 O(n3)

const int M = int(3e2) + 9;
const int N = int(3e2) + 9;
int dp[N][M], cost[N], value[N]; VI adj[N];
int n, m;

void dfs(int u = 0) {
    FLC(dp[u], 0x80);
    DWN_1(i, m, cost[u]) dp[u][i] = value[u];

    for (auto v: adj[u]) {
        dfs(v);
        DWN_1(i, m, cost[u]) {
            FOR_1(j, cost[u], i) {
                checkMax(dp[u][i], dp[u][j] + dp[v][i-j]);
            }
        }
    }
}

int main() {
#ifndef ONLINE_JUDGE
    freopen("in.txt", "r", stdin);
    //freopen("/Users/minakokojima/Documents/GitHub/ACM-Training/Workspace/out.txt", "w", stdout);
#endif
    RD(n, m);
    REP_1(i, n) {
        int p; RD(p, value[i]); cost[i] = 1;
        adj[p].push_back(i);
    }
    dfs();
    cout << dp[0][m] << endl;
}

状态继承 O(n2)

const int N = int(1e5) + 9;
const int M = int(1e5) + 9;
int cost[N], value[N]; VI adj[N];
int n, m;

void dfs(int u, int m, VI& dpu) {
    m -= cost[u];
    for (auto v: adj[u]) {
        VI dpv = dpu; dfs(v, m, dpv);
        FOR_1(i, 0, m) checkMax(dpu[i], dpv[i]);
    }
    m += cost[u];
    DWN_1(i, m, cost[u]) dpu[i] = dpu[i-cost[u]] + value[u];
    REP(i, cost[u]) dpu[i] = -INF;
}

int main() {
#ifndef ONLINE_JUDGE
    freopen("in.txt", "r", stdin);
    //freopen("/Users/minakokojima/Documents/GitHub/ACM-Training/Workspace/out.txt", "w", stdout);
#endif
    RD(n, m);
    REP_1(i, n) {
        int p; RD(p, value[i]); cost[i] = 1;
        adj[p].push_back(i);
    }
    VI dp0; dp0.resize(m+1);
    dfs(0, m, dp0);
    cout << dp0[m] << endl;
}

P1273 有线电视网
https://www.luogu.com.cn/problem/P1273


const int N = (3e3) + 9;
VII adj[N]; int sz[N];
int dp[N][N], bonus[N];
int n, m, z;

bool isLeaf(int u) {
    return u > n-m;
}

void dfs0(int u) {
    sz[u] = isLeaf(u);
    for (auto e: adj[u]) {
        int v = e.fi;
        dfs0(v);
        sz[u] += sz[v];
    }
}

void dfs(int u) {
    FLC(dp[u], 0x80);
    dp[u][0] = 0;

    if (isLeaf(u)) {
        dp[u][1] = bonus[u];
        return;
    }

    for (auto e: adj[u]) {
        int v = e.fi, w = e.se;
        dfs(v);
        DWN_1(i, sz[u], 1) {
            REP_1(j, sz[v]) {
                checkMax(dp[u][i], dp[u][i-j] + dp[v][j] - w);
            }
        }
    }
}

int main(){
#ifndef ONLINE_JUDGE
    freopen("in.txt", "r", stdin);
    //freopen("/Users/minakokojima/Documents/GitHub/ACM-Training/Workspace/out.txt", "w", stdout);
#endif
    RD(n, m); REP_1(u, n-m) {
        Rush {
            int v, c; RD(v, c);
            adj[u].PB({v,c});
        }
    }

    FOR_1(u, n-m+1, n) RD(bonus[u]);

    dfs0(1); dfs(1);
    DWN_1(i, m, 0) {
        if (dp[1][i] >= 0) {
            cout << i << endl;
            return 0;
        }
    }
}

道路重建

https://www.luogu.com.cn/problem/P1272
https://www.luogu.com.cn/problem/U53878


const int N = (1e5) + 9;
VI adj[N]; int sz[N];
int n, m, z;

VI dp[N];
// dp[u][i],保留 u 节点同时子树再保留 i 个节点的子树,最少删多少边

void dfs(int u, int p){

    sz[u] = 1; dp[u].PB(0);

    for (auto v: adj[u]) if (v != p) {
        dfs(v, u);

        REP(i, SZ(dp[u])) dp[u][i] += 1;
        DO(min(sz[v], m+1-sz[u])) dp[u].PB(INF);
        sz[u] += sz[v];

        DWN(i, SZ(dp[u]), 1) {
            REP(j, min(SZ(dp[v]), i)) {
                checkMin(dp[u][i], dp[u][i-1-j] + dp[v][j] - 1);
            }
        }
    }

    if (sz[u] > m) checkMin(z, dp[u][m] + bool(p));
}

signed main(){
#ifndef ONLINE_JUDGE
    freopen("in.txt", "r", stdin);
    //freopen("/Users/minakokojima/Documents/GitHub/ACM-Training/Workspace/out.txt", "w", stdout);
#endif
    RD(n, m); --m; DO(n-1){
        int a, b; RD(a, b);
        adj[a].PB(b);
        adj[b].PB(a);
    }
    z = INF; dfs(1, 0);
    cout << z << endl;
}