【问题描述】
有一树型道路,树中每一结点都有一个标号,同时有一块标有质量的金子,游戏者从最上边根结点出发,遍历若干结点,每经过一个结点都必须拿走该结点的金子。现在规定游戏者拿走的金子数目是有限的,问怎样走才能使得到的金子质量最大?(第一个数是标号,第二个是金子重量)
具体问题:
一棵有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; }
时间: 2024-10-09 22:06:24