HihoCoder第十二周:刷油漆
#1055 : 刷油漆
时间限制:10000ms
单点时限:1000ms
内存限制:256MB
描述
上回说到,小Ho有着一棵灰常好玩的树玩具!这棵树玩具是由N个小球和N-1根木棍拼凑而成,这N个小球都被小Ho标上了不同的数字,并且这些数字都是处于1..N的范围之内,每根木棍都连接着两个不同的小球,并且保证任意两个小球间都不存在两条不同的路径可以互相到达。没错,这次说的还是这棵树玩具的故事!
小Ho的树玩具的质量似乎不是很好,短短玩了几个星期,便掉漆了!
“简直是一场噩梦!”小Ho拿着树玩具眼含热泪道。
“这有什么好忧伤的,自己买点油漆刷一刷不就行了?”小Hi表示不能理解。
“还可以这样?”小Ho顿时兴高采烈了起来,立马跑出去买回来了油漆,但是小Ho身上的钱却不够——于是他只买回了有限的油漆,这些油漆最多能给M个结点涂上颜色,这就意味着小Ho不能够将他心爱的树玩具中的每一个结点都涂上油漆!
小Ho低头思索了半天——他既不想只选一部分结点补漆,也不想找小Hi借钱,但是很快,他想出了一个非常棒的主意:将包含1号结点的一部分连通的结点进行涂漆(这里的连通指的是这一些涂漆的结点可以互相到达并且不会经过没有涂漆的结点),然后将剩下的结点拆掉!
那么究竟选择哪些结点进行涂漆呢?小Ho想了想给每个结点都评上了分——他希望最后留下来,也就是涂漆了的那些结点的评分之和可以尽可能的高!
那么,小Ho该如何做呢?
输入
每个测试点(输入文件)有且仅有一组测试数据。
每组测试数据的第一行为两个整数N、M,意义如前文所述。
每组测试数据的第二行为N个整数,其中第i个整数Vi表示标号为i的结点的评分
每组测试数据的第3~N+1行,每行分别描述一根木棍,其中第i+1行为两个整数Ai,Bi,表示第i根木棍连接的两个小球的编号。
对于100%的数据,满足N<=10^2,1<=Ai<=N, 1<=Bi<=N,1<=Vi<=10^3, 1<=M<=N
小Hi的Tip:那些用数组存储树边的记得要开两倍大小哦!
输出
对于每组测试数据,输出一个整数Ans,表示使得涂漆结点的评分之和最高可能是多少。
样例输入
10 4
370 328750 930 604 732 159 167 945 210
1 2
2 3
1 4
1 5
4 6
4 7
4 8
6 9
5 10
样例输出
2977
现在觉得,很多题都是见识过与没见识过的问题。没见识过的话,就不知道这种思路,想破天也很难做出来。见识过了,了解了这种思路了,那么下一次遇到这种题时会简单很多。
感悟:
1.觉得树中取最大连接的几个点那块用动态规划的思想很棒。
2.从0开始++不行的时候,试着换种思路,从最大值开始--,这种麻烦事碰到不是一次两次了,下把长点心。
这次代码完全自己写的,半夜一直调。。。看见AC的时候很惊讶,很有成就感。
代码:
#include <iostream> #include <string> #include <cstring> #include <vector> using namespace std; vector <int> dp[105]; int value[105]; int N,M; int f[105][105]; int used[105]; void cal(int node) { used[node]=1; f[node][1]=value[node]; int count; int m,m_child; for(count=0;count<dp[node].size();count++) { if(!used[dp[node][count]]) { cal(dp[node][count]); for(m=M;m>=2;m--) { for(m_child=1;m_child<=m-1;m_child++) { f[node][m] = max(f[node][m],f[node][m-m_child]+f[dp[node][count]][m_child]); } } } } } int main() { cin>>N>>M; int count; for(count=1;count<=N;count++) { cin>>value[count]; } for(count=0;count<N-1;count++) { int a,b; cin>>a>>b; dp[a].push_back(b); dp[b].push_back(a); } memset(used,0,sizeof(used)); cal(1); cout<<f[1][M]<<endl; return 0; }
版权声明:本文为博主原创文章,未经博主允许不得转载。