牛客周赛 Round 15 D.游游的树上边染红, 树形dp

原题链接:登录—专业IT笔试面试备考平台_牛客网

思路:用dp[u][1]表示选取了u与他父节点之间的边,dp[u][0]表示未选取。首先,假设j是u的子节点,那么无论是否选取u与父节点的边,均可以加上dp[j][0]的情况。此外,若不选u与父节点之间的边,那么就可以选择u的子节点j与u之间的边,所以dp[u][0]需要加上u与子节点之间最长的边。

状态转移:dp[u][0] += sum(dp[j][0]) + max(dp[j][1] - dp[j][0]);

                dp[u][1] += sum(dp[j][0]);(dp[u][1]初始赋值为u与父节点之间边的权值)

AC代码

#include
using namespace std;
using std::bitset;
typedef pair pll;

#define int long long
const int N = 400010;
int e[N], ne[N], h[N],w[N], idx;
int dp[N][2];

void add(int a, int b, int c)
{
    e[idx] = b;
    ne[idx] = h[a];
    w[idx] = c;
    h[a] = idx++;
}

void dfs(int u, int fa, int wi)
{
    dp[u][1] = wi;
    int d = 0;
    for(int i = h[u]; i != -1; i = ne[i])
    {
        int j = e[i];
        if(j == fa)continue;
        dfs(j, u, w[i]);
        d = max(d, dp[j][1] - dp[j][0]);
        dp[u][0] += dp[j][0];
        dp[u][1] += dp[j][0];
    }
    dp[u][0] += d; 
}

void solve()
{
    int n;
    cin >> n;
    int m = n - 1;
    memset(h, -1, sizeof h);
    while(m--)
    {
        int a, b, c;
        cin >> a >> b >> c;
        add(a, b, c);
        add(b, a, c);
    }
    dfs(1, 0, 0);
    cout << dp[1][0] << endl;
}

signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    int t;
    t = 1;
    //t = read(t);
    while (t--)
    {
        solve();
    }

}

你可能感兴趣的:(牛客,算法,c++,图论,数据结构)