【题目描述】
一棵苹果树有N(1 <= N <= 100)个节点(编号为1~N),每个节点上都有一定数量的苹果,Mary从根节点(编号为1)开始通过K(0 <= K <= 200)个结点,每通过一个节点,她就可以把此节点上的苹果吃掉,询问Mary最多能够吃掉多少个苹果。
【输入描述】
输入多组数据,每组数据格式如下:
第一行输入两个数N、K;
第二行输入N个数,表示每个节点上的苹果数量;
接下来N-1行,每行输入两个数A、B,表示节点A和节点B相连。
【输出描述】
对于每组数据,输出一个数,表示答案。
【输入样例】
2 1
0 11
1 2
3 2
0 1 2
1 2
1 3
【输出样例】
11
2
源代码: #include<cstdio> #include<cstring> #include<algorithm> using namespace std; struct Node { int To,Next; }i[501]; int n,k,Num,f[201][401][2],Head[201],W[201]; void Add(int t1,int t2) //边表。 { i[++Num].To=t2; i[Num].Next=Head[t1]; Head[t1]=Num; } void DFS(int Root,int Mark) { for (int a=Head[Root];a;a=i[a].Next) { int T=i[a].To; if (T==Mark) //无向边判重。 continue; DFS(T,Root); //DFS回溯。 for (int b=k;b>=1;b--) //倒序以防重复。 for (int c=1;c<=b;c++) //断点。 { f[Root][b][0]=max(f[Root][b][0],f[Root][b-c][1]+f[T][c-1][0]); //仔细想想这些常数的含义。 f[Root][b][0]=max(f[Root][b][0],f[Root][b-c][0]+f[T][c-2][1]); f[Root][b][1]=max(f[Root][b][1],f[Root][b-c][1]+f[T][c-2][1]); } } } int main() { while (scanf("%d%d",&n,&k)==2) { Num=0; memset(f,0,sizeof(f)); memset(Head,0,sizeof(Head)); //初始化。 for (int a=1;a<=n;a++) { scanf("%d",&W[a]); for (int b=0;b<=k;b++) f[a][b][0]=f[a][b][1]=W[a]; //赋初值。 } for (int a=1;a<n;a++) { int t1,t2; scanf("%d%d",&t1,&t2); Add(t1,t2); Add(t2,t1); } DFS(1,0); printf("%d ",max(f[1][k][0],f[1][k][1])); } return 0; } /* 设f[i][j][0]表示以i为根节点,走j步,不回到i点的能够得到的最大苹果数,f[i][j][1]表示回到i点的。 则f[i][j][0]可以存在2种转移: (1)走i的其他一些子树,然后返回i,再走T子树,不返回; (2)走T子树,然后返回i,再走i的其他一些子树,不返回; 以此类推,f[i][j][1]可以存在1种转移: 走T子树,然后返回i,再走i的其他一些子树,返回i; 可得状态转移方程: f[i][j][0]=max(f[i][j-k][0]+f[i][k-2][1],f[i][j-k][1]+f[i][k-1][0]); f[i][j][1]=max(f[i][j-k][1]+f[i][k-2][1]); */