我是菜鸡,我是菜鸡,我是菜鸡。。。。重要的事说三遍

算是第一次做树形dp的题吧,不太难。。

园林构成一棵树,root为1,Hi从root出发,有k个园林必须玩,每个园林游玩后会得到权值w[i],最多玩M个园林。

经过的园林必须玩,问可得到的最大权值和。

题目链接:http://hihocoder.com/problemset/problem/1104

经典的树形dp,dp[i][j],表示以i为根的子树选j个结点可得的最大权值和。

这样dp[root][num] = g[son_num][num-1] + w[root];

g[son_num][num-1]类似于对root的儿子结点的子树做背包,g[i][j] = max( g[i-1][j-p] + dp[child_id][p] );

题解不错:http://hihocoder.com/discuss/question/2743

对于必须玩的k个点,他的处理方法我没有看懂。。。。discussion里的不错。。。游玩结点i,那么其祖先结点fa[i]必要也游玩,将这些点设为must,

将must构成的子树缩成一个点,rebuild a new tree,就成了上面说的最普通的树形dp了。

 #include<bits/stdc++.h>

 using namespace std;
const int maxn = + ;
int n, k, m; vector<int> G[maxn], G1[maxn];
int fa[maxn], w[maxn], must[maxn], vis[maxn];
int f[maxn][maxn]; void init(){
for( int i = ; i < maxn; ++i ){
G[i].clear();
G1[i].clear();
}
memset( fa, -, sizeof(fa) );
memset( f, -, sizeof(f) );
memset( must, , sizeof(must) );
} void dfs( int u, int pa ){
fa[u] = pa;
for( int i = ; i < G[u].size(); ++i ){
int v = G[u][i];
if( v == pa )
continue;
dfs( v, u );
}
} void dfs1( int u, int pa ){
if( pa != - ){
if( vis[pa] && !vis[u] )
G1[].push_back(u);
else if( !vis[pa] && !vis[u] )
G1[pa].push_back(u);
} for( int i = ; i < G[u].size(); ++i ){
int v = G[u][i];
if( v == pa )
continue;
dfs1( v, u );
}
} int dp( int root, int num ){
if( num == )
return ;
if( f[root][num] != - )
return f[root][num]; int g[maxn][maxn], son_num = G1[root].size();
memset( g, , sizeof(g) );
for( int i = ; i <= son_num; ++i ){
int child = G1[root][i-];
for( int j = ; j < num; ++j ){
for( int p = ; p <= j; ++p ){
g[i][j] = max( g[i][j], g[i-][j-p] + dp( child, p ) );
}
}
} f[root][num] = g[son_num][num-] + w[root];
return f[root][num];
} void print( int num ){
for( int i = ; i < G1[num].size(); ++i )
cout << G1[num][i] << " ";
cout << endl;
} void solve(){
dfs(, -); //must节点压缩
int ans = , cnt = ;
memset( vis, , sizeof(vis) );
for( int i = ; i <= n; ++i ){
if(must[i]){
int u = i;
while(u != - && !vis[u]){
vis[u] = ;
cnt++, ans += w[u];
u = fa[u];
}
}
}
//cout << "ans: " << ans << endl; if( cnt > m ){
printf("-1\n");
return;
} //rebuild tree
dfs1( , - ); w[] = ans;
//cout << "m-cnt: " << m - cnt << endl;
ans = dp( , m-cnt+ );
//cout << "f: " << f[8][3] << endl; printf("%d\n", ans);
} int main(){
//freopen("1.in", "r", stdin);
init();
scanf("%d%d%d", &n, &k, &m);
for( int i = ; i <= n; ++i ){
scanf("%d", &w[i]);
} int t;
for( int i = ; i <= k; ++i ){
scanf("%d", &t);
must[t] = ;
} int a, b;
for( int i = ; i <= n-; ++i ){
scanf("%d%d", &a, &b);
G[a].push_back(b), G[b].push_back(a);
} solve(); return ;
}

当然,也可以不需要g数组,直接当一维背包来做

dp[root][x] = max( dp[root][x], dp[root][x-y] + dp[child_id][y] );

 #include<bits/stdc++.h>

 using namespace std;
const int maxn = + ;
int n, k, m; vector<int> G[maxn], G1[maxn];
int fa[maxn], w[maxn], must[maxn], vis[maxn];
int f[maxn][maxn]; void init(){
for( int i = ; i < maxn; ++i ){
G[i].clear();
G1[i].clear();
}
memset( fa, -, sizeof(fa) );
memset( f, -, sizeof(f) );
memset( must, , sizeof(must) );
} void dfs( int u, int pa ){
fa[u] = pa;
for( int i = ; i < G[u].size(); ++i ){
int v = G[u][i];
if( v == pa )
continue;
dfs( v, u );
}
} void dfs1( int u, int pa ){
if( pa != - ){
if( vis[pa] && !vis[u] )
G1[].push_back(u);
else if( !vis[pa] && !vis[u] )
G1[pa].push_back(u);
} for( int i = ; i < G[u].size(); ++i ){
int v = G[u][i];
if( v == pa )
continue;
dfs1( v, u );
}
} void dp(int root, int pa){
f[root][] = w[root];
for( int i = ; i < G1[root].size(); ++i ){
int v = G1[root][i];
if( v == pa )
continue;
dp( v, root );
for( int x = m; x >= ; --x ){
for( int y = ; y < x; ++y ){
f[root][x] = max( f[root][x], f[root][x-y] + f[v][y] );
}
}
}
} void solve(){
dfs(, -); //must½ÚµãѹËõ
int ans = , cnt = ;
memset( vis, , sizeof(vis) );
for( int i = ; i <= n; ++i ){
if(must[i]){
int u = i;
while(u != - && !vis[u]){
vis[u] = ;
cnt++, ans += w[u];
u = fa[u];
}
}
}
//cout << "ans: " << ans << endl; if( cnt > m ){
printf("-1\n");
return;
} //rebuild tree
dfs1( , - ); w[] = ans;
dp(, -);
printf("%d\n", f[][m-cnt+]);
} int main(){
//freopen("1.in", "r", stdin);
init();
scanf("%d%d%d", &n, &k, &m);
for( int i = ; i <= n; ++i ){
scanf("%d", &w[i]);
} int t;
for( int i = ; i <= k; ++i ){
scanf("%d", &t);
must[t] = ;
} int a, b;
for( int i = ; i <= n-; ++i ){
scanf("%d%d", &a, &b);
G[a].push_back(b), G[b].push_back(a);
} solve(); return ;
}

hiho一下第76周《Suzhou Adventure》的更多相关文章

  1. 圆内,求离圆心最远的整数点 hiho一下第111周 Farthest Point

    // 圆内,求离圆心最远的整数点 hiho一下第111周 Farthest Point // 思路:直接暴力绝对T // 先确定x范围,每个x范围内,离圆心最远的点一定是y轴两端的点.枚举x的范围,再 ...

  2. HihoCoder 1104 : Suzhou Adventure(树形DP)

    Suzhou Adventure 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 Little Hi is taking an adventure in Suzhou n ...

  3. hiho一下 第115周:网络流一•Ford-Fulkerson算法 (Edmond-Karp,Dinic,SAP)

    来看一道最大流模板水题,借这道题来学习一下最大流的几个算法. 分别用Edmond-Karp,Dinic ,SAP来实现最大流算法. 从运行结过来看明显SAP+当前弧优化+gap优化速度最快.   hi ...

  4. 【hiho一下第77周】递归-减而治之 (MS面试题:Koch Snowflake)

    本题是一道微软面试题,看起来复杂,解出来会发现其实是一个很简单的递归问题,但是这道题的递归思路是很值得我们反复推敲的. 原题为hihocoder第77周的题目. 描述 Koch Snowflake i ...

  5. hiho一下 第207周

    题目1 : The Lastest Time 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 What is latest time you can make with ...

  6. hiho一下第128周 后缀自动机二·重复旋律5

    #1445 : 后缀自动机二·重复旋律5 时间限制:10000ms 单点时限:2000ms 内存限制:512MB 描述 小Hi平时的一大兴趣爱好就是演奏钢琴.我们知道一个音乐旋律被表示为一段数构成的数 ...

  7. 【hiho一下】第一周 最长回文子串

    题目1:最长回文子串 题目原文:http://hihocoder.com/contest/hiho1/problem/1 [题目解读] 题目与 POJ 3974 palindrome 基本同样.求解最 ...

  8. Solution: 最近公共祖先·一 [hiho一下 第十三周]

    题目1 : 最近公共祖先·一 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 小Ho最近发现了一个神奇的网站!虽然还不够像58同城那样神奇,但这个网站仍然让小Ho乐在其中 ...

  9. hiho一下十六周 RMQ-ST算法

    RMQ-ST算法 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 小Hi和小Ho在美国旅行了相当长的一段时间之后,终于准备要回国啦!而在回国之前,他们准备去超市采购一些当 ...

随机推荐

  1. Eclipse的菜单简介

    在Eclipse工作台的上方提供了菜单栏,该菜单栏包含了实现Eclipse各项功能的命令,并且与编辑器相关,即菜单栏中的菜单项与当前编辑器内打开的文件是关联的.例如,编辑器内没有打开任何文件,那么,将 ...

  2. Leetcode0100--Same Tree 相同树

    [转载请注明]http://www.cnblogs.com/igoslly/p/8707664.html 来看一下题目: Given two binary trees, write a functio ...

  3. 从XMLHttpRequest中获取请求的URL

    在编写Ajax通用错误处理程序时,经常需要记录发生错误的XMLHttpRequest的请求URL.但查询文档,并未找到从XMLHttpRequest中获取请求URL的方法. 在javascript - ...

  4. THREE.js代码备份——webgl - custom attributes [lines](自定义字体显示、控制字图的各个属性)

    <!DOCTYPE html> <html lang="en"> <head> <title>three.js webgl - cu ...

  5. 10--C++多态

    C++多态 C++多态技术 摘要 本文描述了C++中的各种多态性.重点阐述了面向对象的动态多态和基于模板的静态多态,并初步探讨了两种技术的结合使用. 关键词 多态  继续  虚函数  模板  宏  函 ...

  6. BZOJ 1585: Earthquake Damage 2 地震伤害 网络流 + 最小割

    Description Farmer John的农场里有P个牧场,有C条无向道路连接着他们,第i条道路连接着两个牧场Ai和Bi,注意可能有很多条道路连接着相同的Ai和Bi,并且Ai有可能和Bi相等.F ...

  7. RabbitMQ出现服务启动几秒退出问题

    最近在学习rebbitmq, 1.首先安装了otp_win64_20.3, 2.erlang安装完成需要配置erlang环境变量: 这个是新建的 文档是:ERLANG_HOME D:\develop\ ...

  8. 关于vcruntime140D.dll丢失问题

    电脑磁盘占用率100%,又检测出硬盘磁道坏了,要么装win7,要么换个SSD,无奈重装环境. 遇到这个问题,之前的电脑就遇到过,网上交的下载这个文件装到C盘Windows的SysWOW64,对于实验室 ...

  9. 结构体、枚举、联合(day14)

    一个存储区的地址必须是它自身大小的整数倍 (double类型存储区的地址只需要是4的 整数倍) 这个规则叫数据对齐 结构体里面的子存储区通常也需要遵守数据 对齐的规则 数据对齐会造成结构体内部子存储区 ...

  10. SpringBoot背景

    1.SpringBoot的产生背景:随着spring日益发展,丰富的框架和组件大大简化了java项目开发过程,经过多年的实践,得到了很多人的认可,但是Spring的严重依赖XML配置文件,严重导致项目 ...