• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录

会点儿code

  • 博客园
  • 联系
  • 订阅
  • 管理

公告

View Post

ZOJ3201 Tree of Tree

Tree of Tree


Time Limit: 1 Second      Memory Limit: 32768 KB

You're given a tree with weights of each node, you need to find the maximum subtree of specified size of this tree.

Tree Definition
A tree is a connected graph which contains no cycles.

Input

There are several test cases in the input.

The first line of each case are two integers N(1 <= N <= 100), K(1 <= K <= N), where N is the number of nodes of this tree, and K is the subtree's size, followed by a line with N nonnegative integers, where the k-th integer indicates the weight of k-th node. The following N - 1 lines describe the tree, each line are two integers which means there is an edge between these two nodes. All indices above are zero-base and it is guaranteed that the description of the tree is correct.

Output

One line with a single integer for each case, which is the total weights of the maximum subtree.

Sample Input

3 1
10 20 30
0 1
0 2
3 2
10 20 30
0 1
0 2

Sample Output

30
40
月赛难得和long1兄合作,十分愉快。虽然身在Turkey,但是long1兄不忘参加月赛提高自己,令我十分敬佩。
当时long1兄匪夷所思地写出这道树型DP,我不是很理解,特此研究代码,总结下。

// 树型DP,DFS

// 思路:
// F[T][k]表示以T为根节点,大小为k的树所能得到的最大权和
// 从任意一点开始做DFS,确立节点的双亲-孩子关系
// DFS完一颗子树后,更新其双亲节点的DP值

// 更新过程为: (假设当前双亲点为T,刚遍历完子树S)
// 枚举T树的大小k,枚举T树上的点不落在S树上的个数k',那么将有k-k'个点落在S树上
// F[T][k] = max{F[T][k']+F[S][k-k'] | 1<=k'<=k} (可以是k-1)

// 这里要注意下,如果已经DFS过的子树总共只有n个点,那么F[T]最多只能更新到F[T][n+1]
// 所有子树DFS完毕后,F[T]的值才算计算完毕.

// 一开始想,为什么F[T][k]的计算过程中,不考虑T的祖先节点T',因为T'也可以看成是T的孩子
// 其实在DFS回归的过程中,会计算T'的DP值,而T是T'的子树.所以上述情况已经在计算T'的过程中被考虑进去了

// 时间复杂度O(n^3)

#include <iostream>
#include <vector>

using namespace std;

int g_nNode, g_k;

int w[100];                                   // 节点权值
vector<int> conn[100];              // 邻接链表
int F[100][101];                     // DP数组

inline int mmax(int a, int b) {
       return a>b?a:b;
}

void DP(int node, int child) {
       int sz;
       int k;
       for(sz=g_k; sz>=1; sz--) {
              // 以node为根的sz大小的子树
              for(k=sz; k>=1; k--) {
                     // 其中k个节点在node上或者之前遍历过的node的子树上, sz-k个节点在child树上
                     // F[node][sz]均从F[node][sz-i]求得,所以这里按照sz递减的顺序计算以免新DP值覆盖前一次DP值
                     F[node][sz] = mmax(F[node][sz], F[node][k] + F[child][sz-k]);
              }
       }
}

void DFS(int node, int parent) {
       F[node][1] = w[node];

       int child;
       for(int i=0; i<(int)conn[node].size(); i++) {
              child = conn[node][i];
              if( child == parent )
                     continue;
              DFS(child, node);              // DFS子树
              DP(node, child);              // 子树DFS完毕后更新当前点的DP值
       }
}

int main() {
       while( scanf("%d %d", &g_nNode, &g_k) != EOF ) {
              // 输入,以及建立邻接矩阵
              int i;
              for(i=0; i<g_nNode; i++) {
                     scanf("%d", w+i);
                     conn[i].resize(0);
              }

              int from, to;
              for(i=0; i<g_nNode-1; i++) {
                     scanf("%d %d", &from, &to);
                     conn[from].push_back(to);
                     conn[to].push_back(from);
              }

              memset(F, 0, sizeof(F));
              DFS(0, 0);

              // 取以任意点为根,大小为k的树中权最大的一个
              int res = 0;
              for(i=0; i<g_nNode; i++) {
                     res = mmax(res, F[i][g_k]);
              }
              printf("%d\n", res);
       }

       return 0;
}

posted on 2009-05-04 22:51  曹某  阅读(327)  评论(0)    收藏  举报

刷新页面返回顶部
 
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3