【无标题】

自下而上的树形DP

01例题

选择若干个点,使得没有相邻的两个点均被选择。最大化被选择的点的点权和。

3
1 2 3
2 1
3 1
=>5
​
#include<bits/stdc++.h>
using namespace std;
const int N = 100005;
int n, a[N];
long long dp[N][2];
vector<int> e[N];
void dfs(int u){
    for (auto v : e[u]){
        dfs(v);
        dp[u][1] += dp[v][0];
        dp[u][0] += max(dp[v][0], dp[v][1]);
    }
    dp[u][1] += a[u];
}
int main()
{
    cin >> n;
    set<int>st;
    for (int i = 1; i <= n; i++)cin >> a[i], st.insert(i);
    for (int i = 1, x, y; i < n; i++){
        cin >> x >> y;
        e[y].push_back(x);
        st.erase(x);
    }
    int rt = *st.begin();
    dfs(rt);
    cout << max(dp[rt][0], dp[rt][1]);
    return 0;
}
02最小点覆盖

#include<bits/stdc++.h>
using namespace std;
const int N = 100005;
int n, dp[N][2];
vector<int> e[N];
void dfs(int u,int fa ){
    for (auto v : e[u]){
        if (v == fa)continue;
        dfs(v, u);
        dp[u][0] += dp[v][1];
        dp[u][1] += min(dp[v][0], dp[v][1]);
    }
    dp[u][1] += 1;
}
​
int main()
{
    cin >> n;
    for (int i = 1; i <n; i++)
    {
        int x, y;
        cin >> x >> y;
        e[x].push_back(y);
        e[y].push_back(x);
    }
    dfs(1, 0);
        cout << min(dp[1][0], dp[1][1]);
    return 0;
}
03最小支配集

#include <bits/stdc++.h>
using namespace std;
const int N=100005;
vector<int>e[N];
long long a[N],dp[N][3];
int d[N];
int n;
void dfs(int u)
{
    long long minn=1e18;
    for (auto v:e[u])
    {
        dfs(v);
        dp[u][0]+=min({dp[v][0],dp[v][1],dp[v][2]});
        dp[u][1]+=min(dp[v][0],dp[v][1]);
        minn=min(minn,dp[v][0]-min(dp[v][0],dp[v][1]));
        dp[u][2]+=dp[v][1];
    }
    dp[u][0]+=a[u];
    dp[u][1]+=minn;
}
int main()
{
    cin.tie(0);
    cout.tie(0);
    ios::sync_with_stdio(0);
    cin>>n;
    for (int i=1;i<=n;++i)
    {
        int id,m;
        cin>>id;
        cin>>a[id];
        cin>>m;
        while (m--)
        {
            int x;
            cin>>x;
            e[id].push_back(x);
            d[x]++;
        }
    }
    int rt;
    for (int i=1;i<=n;++i)
        if (d[i]==0) rt=i;
    dfs(rt);
    cout<<min(dp[rt][0],dp[rt][1]);
    return 0;
}
  • 18
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值