ZOJ 3201解题报告
2015-03-17 00:47
316 查看
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
Sample Output
Author: LIU, Yaoting
Source: ZOJ Monthly, May 2009
这道题是一道比较经典的树形dp的题。给一棵树,求出这棵树中个数为k的子树的权值的最大值。首先要说的是选出子树的大小为k,而不是从树中任选k个结点,这样是不一样的。。然后需要再次强调的就是dfs的顺序对于dp的顺序影响。本题中可以很容易的得出状态为dp[u][j]表示以u为根节点的有j个结点的子树。然后状态怎么转移呢?假设此时访问到u的子节点v。那么从v中取i个结点。然后需要再从其他结点中选j-i个结点。但是选这j-i个结点该怎么选呢?考虑dp[u][j-i],因为此时访问到v,那么在v之前必然访问过u和其他的一些与u相连的子节点。dp[u][j]此时表示的是已经访问的子树中有j个结点的最大值。通过dfs的不断更新,dp[u][j]不断更新。当u的子节点访问完以后dp[u][i]的值才确定。因而dfs的过程也是子问题不断扩大的过程。考虑动态规划中原问题依赖于子问题。在树形dp中子问题就是dfs的过程中伴随产生的。。随着dfs访问的子节点不断增多,子问题不断扩大。。这样深刻的思考之后发现动态规划的思路是很清晰的。dfs是动态变化,动态更新的,dp的值也是一样。
然后还要强调的是dp的顺序问题。我们得到状态转移方程dp[u][j]=max(dp[u][j],dp[v][i]+dp[u][j-i])。dp[u][j-i]是未访问v之前的那些结点对u的更新结果。如果j从1~k的话,当dp[u][k]调用时,max里边的dp[u][j-i]是被v修改过以后的,这样再加上dp[v][i]的值就不对了。因而在本题的dp过程中还要考虑清楚j要从k~1按照降序来dp。这个原因要理解透彻。
还有本题中需要注意的地方是最后的对所有点的dp值取最大值。这是为啥?dp[v][k]求出来的是v所在子树的最大值。而如果有k个结点还有一些结点是v的祖先节点怎么办。其实dp的含义还是需要再精确一下,这个题中dp的含义还包含u是这k个结点的子树中深度最浅的结点(叶子结点深度最深,这个结点u离根节点比其他k-1个更近)。因而如果v是选出来的这个含有k个结点的子树中的一个结点,并且k个结点中还有结点在v的上方,那么我们不用考虑,这个值就交给v上面那个离根节点最近的祖先结点来完成了。因而还要想到dp表示的状态中这一层隐含的意思。
相信对树形dp研究之后,发现dfs的过程还有许多值得思考回味的地方。
参考代码:
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
Author: LIU, Yaoting
Source: ZOJ Monthly, May 2009
这道题是一道比较经典的树形dp的题。给一棵树,求出这棵树中个数为k的子树的权值的最大值。首先要说的是选出子树的大小为k,而不是从树中任选k个结点,这样是不一样的。。然后需要再次强调的就是dfs的顺序对于dp的顺序影响。本题中可以很容易的得出状态为dp[u][j]表示以u为根节点的有j个结点的子树。然后状态怎么转移呢?假设此时访问到u的子节点v。那么从v中取i个结点。然后需要再从其他结点中选j-i个结点。但是选这j-i个结点该怎么选呢?考虑dp[u][j-i],因为此时访问到v,那么在v之前必然访问过u和其他的一些与u相连的子节点。dp[u][j]此时表示的是已经访问的子树中有j个结点的最大值。通过dfs的不断更新,dp[u][j]不断更新。当u的子节点访问完以后dp[u][i]的值才确定。因而dfs的过程也是子问题不断扩大的过程。考虑动态规划中原问题依赖于子问题。在树形dp中子问题就是dfs的过程中伴随产生的。。随着dfs访问的子节点不断增多,子问题不断扩大。。这样深刻的思考之后发现动态规划的思路是很清晰的。dfs是动态变化,动态更新的,dp的值也是一样。
然后还要强调的是dp的顺序问题。我们得到状态转移方程dp[u][j]=max(dp[u][j],dp[v][i]+dp[u][j-i])。dp[u][j-i]是未访问v之前的那些结点对u的更新结果。如果j从1~k的话,当dp[u][k]调用时,max里边的dp[u][j-i]是被v修改过以后的,这样再加上dp[v][i]的值就不对了。因而在本题的dp过程中还要考虑清楚j要从k~1按照降序来dp。这个原因要理解透彻。
还有本题中需要注意的地方是最后的对所有点的dp值取最大值。这是为啥?dp[v][k]求出来的是v所在子树的最大值。而如果有k个结点还有一些结点是v的祖先节点怎么办。其实dp的含义还是需要再精确一下,这个题中dp的含义还包含u是这k个结点的子树中深度最浅的结点(叶子结点深度最深,这个结点u离根节点比其他k-1个更近)。因而如果v是选出来的这个含有k个结点的子树中的一个结点,并且k个结点中还有结点在v的上方,那么我们不用考虑,这个值就交给v上面那个离根节点最近的祖先结点来完成了。因而还要想到dp表示的状态中这一层隐含的意思。
相信对树形dp研究之后,发现dfs的过程还有许多值得思考回味的地方。
参考代码:
#include<cstdio> #include<iostream> #include<cmath> #include<cstring> #include<algorithm> #include<string> #include<vector> #include<map> #include<set> #include<stack> #include<queue> #include<ctime> #include<cstdlib> #include<iomanip> #include<utility> #define pb push_back #define mp make_pair #define CLR(x) memset(x,0,sizeof(x)) #define _CLR(x) memset(x,-1,sizeof(x)) #define REP(i,n) for(int i=0;i<n;i++) #define Debug(x) cout<<#x<<"="<<x<<" "<<endl #define REP(i,l,r) for(int i=l;i<=r;i++) #define rep(i,l,r) for(int i=l;i<r;i++) #define RREP(i,l,r) for(int i=l;i>=r;i--) #define rrep(i,l,r) for(int i=l;i>r;i--) #define read(x) scanf("%d",&x) #define put(x) printf("%d\n",x) #define ll long long #define lson l,m,rt<<1 #define rson m+1,r,rt<<11 using namespace std; int dp[110][110]; int n,k; int a[110]; vector<int>G[110]; void dfs(int u,int rt) { int len=G[u].size(); dp[u][1]=a[u]; rep(i,0,len) { int v=G[u][i]; if(v==rt) continue; dfs(v,u); RREP(j,k,1) REP(l,1,j) dp[u][j]=max(dp[u][j],dp[u][l]+dp[v][j-l]); } } int main() { while(~scanf("%d%d",&n,&k)) { CLR(dp); rep(i,0,n) read(a[i]); rep(i,0,n-1) { int u,v; scanf("%d%d",&u,&v); G[u].pb(v); G[v].pb(u); } dfs(0,-1); int ans=0; rep(i,0,n) ans=max(ans,dp[i][k]); printf("%d\n",ans); REP(i,0,100) G[i].clear(); } }
相关文章推荐
- zoj 3212 K-Nice 解题报告
- ZOJ2321解题报告
- [解题报告]ZOJ 1001
- 【原创】ZOJ_1649 Rescue 解题报告
- ZOJ 3687 The Review Plan I 解题报告
- ZOJ1006解题报告
- ZOJ Problem Set - 2412解题报告
- zoj 3164 Cookie choice 解题报告
- ZOJ 3804--解题报告
- ZOJ 3721 Final Exam Arrangement 解题报告
- 【解题报告】 ZOJ 3640 Help Me Escape - 期望dp
- ZOJ 3689 Digging 解题报告
- ZOJ 1610 解题报告
- ZOJ 1115 解题报告
- ZOJ 3313-3321 The 10th Zhejiang University Programming Contest 部分题目解题报告
- ZOJ2388解题报告
- ZOJ - 1098 Simple Computer 解题报告
- zoj 1002解题报告
- ZOJ 3716 Ribbon Gymnastics 解题报告
- ZOJ 1914 Arctic Network(解题报告)