树形DP——hiho 1055

  • 题目链接:
    https://hihocoder.com/problemset/problem/1055

  • 分析:
    给出一棵N个节点的树,一共N-1条边,每个节点都有其价值,要求从中选出互相连接的M个节点(包括节点1)使得其价值和最大。

  • 题解:
    设dp[i][j]为第i个节点下的选择j个节点时(包括第i个节点)的最大价值。

    我们先把每一个dp[i][1]都初始化每个节点自己的价值,表示单独选择i节点时候得到的最大价值。然后从节点1开始DFS(题意要求必须包括节点1),每搜到它下面一个节点,再以那个节点进行DFS。DFS返回这个节点下的子节点数目。然后更新DP数组:

int dfs(int u, int m) //计算节点个数,同时更新dp数组
{
    int sons = 1;  //子节点个数初始化为1,即自己本身
    int num;
    for(int i=head[u]; i!=-1; i=edge[i].next)
    {
        int v = edge[i].v; //取出相连的第一个节点
        num = dfs(v, m-1); //计算v节点下一共有多少个子节点,同时也会更新dp[v]下面的最大值。
        for(int j=m;j>=1;j--)
        {
            for(int k=1; k<=num && k//j表示u节点下一共取多少个节点,k表示v节点下一共取多少个节点,这样遍历一遍更新出最大的dp[u][j]值。
            }
        }
        sons += num;
    }
    return sons;//返回节点数
}
  • AC代码:
    这里写图片描述
/*************************************************************************
    > File Name: 1055.cpp
    > Author: Akira 
    > Mail: [email protected] 
    > Created Time: 2016年10月07日 星期五 14时21分56秒
 ************************************************************************/

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
typedef long long LL;
typedef unsigned long long ULL;
typedef long double LD;
#define MST(a,b) memset(a,b,sizeof(a))
#define CLR(a) MST(a,0)
#define Sqr(a) ((a)*(a))
using namespace std;

#define MaxN 110
#define MaxM MaxN*2
#define INF 0x3f3f3f3f
#define bug cout<<88888888<
#define MIN(x,y) (x
#define MAX(x,y) (x>y?x:y)

int N, M;
int dp[MaxN][MaxN];

struct Edge
{
    int u,v;
    int next;
}edge[MaxM];
int head[MaxN];
int cont;

void init()
{
    CLR(dp);
    MST(head, -1);
    cont = 0;
}

void add(int u, int v)
{
    edge[cont].v = v;
    edge[cont].next = head[u];
    head[u] = cont++;
}

int dfs(int u, int m)
{
    int sons = 1;
    int num;

    for(int i=head[u]; i!=-1; i=edge[i].next)
    {
        int v = edge[i].v;
        num = dfs(v, m-1);
        for(int j=m;j>=1;j--)
        {
            for(int k=1; k<=num && kreturn sons;
}

int main()
{
    while(~scanf("%d%d", &N, &M))
    {
        init();
        for(int i=1;i<=N;i++)
        {
            scanf("%d", &dp[i][1]);
        }
        int a, b;
        for(int i=1;iscanf("%d%d", &a, &b);
            add(a, b);
        }
        dfs(1, M);
        cout << dp[1][M] << endl;
    }
}

你可能感兴趣的:(ACM算法(题解):,动态规划,——树形DP)