树形DP

hdu1520

题意:给定一棵关系树,每个节点有个权值,子节点和父节点不能同时选,问最后能选的最大价值是多少?

点u有两个状态,选 - dp[u][1],不选 - dp[u][0]

设v为儿子结点,则状态转移方程为:

dp[u][1] = sum(dp[v][0])     说明:父节点选后,儿子节点都不能选

dp[u][0] = sum( max(dp[v][0], dp[v][1]) )    说明:父节点不选时,子节点可选可不选,取决于值的大小 

从叶子节点开始往根节点遍历,因此用dfs,在回溯阶段更新。

/*
 *
 * 树形DP
 *
 
*/

#include <iostream>
#include <cstring>
using namespace std;

#define N 6010
#define M 12010

int head[N], eNum;
struct Edge
{
    int e, next;
}edge[M];

int dp[N][2], num[N];

int max(int x, int y)
{
    return x > y ? x : y;
}

void AddEdge(int u, int v)
{
    edge[eNum].e = v;
    edge[eNum].next = head[u];
    head[u] = eNum++;
}

void dfs(int u, int fa)
{
    //if(vis[u]) return ;
    
//vis[u] = 1;
    for(int i = head[u]; i != -1; i = edge[i].next)
    {
        int v = edge[i].e;
        if(v == fa) continue;
        dfs(v, u);
        dp[u][1] += dp[v][0];
        dp[u][0] += max(dp[v][0], dp[v][1]);
    }
    dp[u][1] += num[u];
}

int main()
{
    int n;
    while(cin >> n)
    {

    for(int i=1; i<=n; i++)
        cin >> num[i];
    memset(dp,0,sizeof(dp));
    memset(head,-1,sizeof(head));
    //memset(vis,0,sizeof(vis));
    eNum = 0;

    int u, v;
    while(cin >> u >> v)
    {
        if(u==0 && v==0)
            break;

        AddEdge(u, v);
        AddEdge(v, u);
    }
    dfs(10);
    cout << max(dp[1][0], dp[1][1]) << endl;
    }
    return 0;
}


/*
 *
 * 树形DP
 *
 
*/

#include <iostream>
#include <cstring>
using namespace std;

#define N 6010
#define M 12010

int head[N], eNum;
struct Edge
{
    int e, next;
}edge[M];

int dp[N][2], num[N];

int max(int x, int y)
{
    return x > y ? x : y;
}

void AddEdge(int u, int v)
{
    edge[eNum].e = v;
    edge[eNum].next = head[u];
    head[u] = eNum++;
}

void dfs(int u, int fa)
{
    //if(vis[u]) return ;
    
//vis[u] = 1;
    for(int i = head[u]; i != -1; i = edge[i].next)
    {
        int v = edge[i].e;
        if(v == fa) continue;
        dfs(v, u);
        dp[u][1] += dp[v][0];
        dp[u][0] += max(dp[v][0], dp[v][1]);
    }
    dp[u][1] += num[u];
}

int main()
{
    int n;
    while(cin >> n)
    {

    for(int i=1; i<=n; i++)
        cin >> num[i];
    memset(dp,0,sizeof(dp));
    memset(head,-1,sizeof(head));
    //memset(vis,0,sizeof(vis));
    eNum = 0;

    int u, v;
    while(cin >> u >> v)
    {
        if(u==0 && v==0)
            break;

        AddEdge(u, v);
        AddEdge(v, u);
    }
    dfs(10);
    cout << max(dp[1][0], dp[1][1]) << endl;
    }
    return 0;
}
View Code 
原文地址:https://www.cnblogs.com/byluoluo/p/3383445.html