码迷,mamicode.com
首页 > 其他好文 > 详细

拾金子

时间:2016-08-16 21:43:52      阅读:143      评论:0      收藏:0      [点我收藏+]

标签:

【问题描述】 

有一树型道路,树中每一结点都有一个标号,同时有一块标有质量的金子,游戏者从最上边根结点出发,遍历若干结点,每经过一个结点都必须拿走该结点的金子。现在规定游戏者拿走的金子数目是有限的,问怎样走才能使得到的金子质量最大?(第一个数是标号,第二个是金子重量)

具体问题:

一棵有n个结点的树(结点标号是1~n),从中找m个点,使这些点连通并包含根结点,并使得所有点的权值(金子质量)和最大。(如果包含10号结点,则必须包含9号和1号结点,因为到达10时必须经过9和1结点)。一定含有根的共m个结点的最大连通分支。

【输入描述】

第一行:n、m;

以后n行,每行是:标号、父结点、金子质量。父亲结点为0的结点是根。

【输出描述】

一行一个整数得到的最大和。

【输入样例】

 

10 5
2 9 9
6 9 1
1 9 1
3 2 1
4 2 1
5 2 1
7 6 4
8 6 6
10 1 20
9 0 1

【输出样例】

32

源代码:

#include<cstdio>
#include<algorithm>
using namespace std;
int m,n,Root(0),i[1001],Left[1001],Right[1001],f[1001][1001];
void DP(int T,int S) //树形背包。
{
    if (!T||!S)
    {
        f[T][S]=0;
        return;
    }
    if (f[T][S])
      return;
    f[T][S]=0;
    for (int a=0;a<S;a++)
    {
        DP(Left[T],a);
        DP(Right[T],S-a-1);
        f[T][S]=max(f[T][S],f[Left[T]][a]+f[Right[T]][S-a-1]+i[T]);
    }
}
int main()
{
    scanf("%d%d",&n,&m);
    for (int a=1;a<=n;a++)
    {
        int t1,t2;
        scanf("%d%d",&t1,&t2);
        scanf("%d",&i[t1]); //节点金子的价值。
        if (!t2)
          Root=t1; //根节点。
        else
          if (Left[t2]) //左右儿子存储。
            Left[t2]=t1;
          else
            Right[t2]=t1;
    }
    DP(Root,m);
    printf("%d",f[Root][m]);
    return 0;
}

 

拾金子

标签:

原文地址:http://www.cnblogs.com/Ackermann/p/5777934.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!