1、poj 115 TELE

  题意:一个树型网络上有n个结点,1~n-m为信号传送器,n-m+1~n为观众,当信号传送给观众后,观众会付费观看,每铺设一条道路需要一定费用。现在求以1为根,使得收到观众的费用-铺设道路的费用>=0的情况下,能最多给多少个观众观看?

  思路:树形dp,dp[i][j]表示以i为根的子树中选择j个观众(叶子)最大的收益。

  ①如果当前结点为叶子结点,那么其dp[i][0]=0,dp[i][1]=val[i].

  ②如果为其他结点,则dp[i][j]=max(dp[i][j],dp[i][j-k]+dp[son][k]-cost)(i:max->0;j:0->max)(表示当前结点选j个叶子,其中k个叶子来自son这棵子树).每个结点的容量为以其为根的子树的所有叶结点数目,可以通过dp回溯累加。

 #include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn = ;
const int maxe = ;
const int INF = 0x3f3f3f;
int wson[maxn];//以i为根的子树的容量(可选的叶子数目)
int val[maxn];
struct edge
{
int from, to, cost, next;
edge(int ff=,int tt=,int cc=,int nn=):from(ff),to(tt),cost(cc),next(nn){ }
}Edge[maxe];
int Head[maxn],totedge;
int n, m;//1为根,2~n-m为传送器,n-m+1~n为观众(叶子)
int dp[maxn][maxn];//dp[i][j]表示以i为子树选择j个叶子的最大v(叶子值-路值)
bool vis[maxn];//表示该点是否已经经过 void Init()
{
memset(Edge, , sizeof(Edge));
memset(Head, -, sizeof(Head));
memset(dp, -INF, sizeof(dp));
memset(vis, , sizeof(vis));
totedge = ;
} void DP(int now, int pre)
{
vis[now] = true;
if (now >= n - m + )
{//如果为叶子
dp[now][]=,dp[now][] = val[now], wson[now] = ;
return;
}
else dp[now][] = ;
for (int e = Head[now]; e != -; e = Edge[e].next)
{
int u = Edge[e].to, w = Edge[e].cost;
if (vis[u]) continue;
DP(u, now);
wson[now] += wson[u];
for (int j = wson[now]; j >= ; j--)
{//枚举当前结点选择叶子个数(从大往小,01背包)
for (int k = ; k <= min(wson[u],j); k++)
{//枚举子节点的叶子个数
dp[now][j] = max(dp[now][j], dp[now][j - k] + dp[u][k] - w);
}
}
}
} void AddEdge(int from, int to, int cost)
{
Edge[++totedge] = edge(from, to, cost,Head[from]);
Head[from] = totedge;
Edge[++totedge] = edge(to, from, cost, Head[to]);
Head[to] = totedge;
} int main()
{
while (~scanf("%d%d", &n, &m))
{
Init();
for (int i = ; i <= n - m; i++)
{
int k;
scanf("%d", &k);
for (int j = ; j <= k; j++)
{
int to, v;
scanf("%d%d", &to, &v);
AddEdge(i, to, v);
}
}
for (int i = n - m + ; i <= n; i++) scanf("%d", val + i);
DP(, );
for (int i = m; i >= ; i--)
{
if (dp[][i] >= )
{
printf("%d\n",i);
break;
}
}
}
return ;
}

2、poj 2486 Apple Tree

  题意:有棵树,每个结点上有权值。从结点1出发走K步,求能走到的点的权值之和最大。

  思路:dp[i][j][0]表示从结点i走j步不会到i时的最大值,dp[i][j][1]表示从结点i走j步回到结点i时最大值。

①回到结点u:从u出发,要回到u,需要多走两步u-v,v-u,分配给v子树k步,其他子树j-k步,都返回:
    dp[u][j][1]=max(dp[u][j][1],dp[u][j-k-2][1]+dp[v][k][1])
②不回到结点u:

  先从其他子树回到u,再在子树v走k步,不回到u:
    dp[u][j][0]=max(dp[u][j][0],dp[u][j-k-1][1]+dp[v][k][0])
  或者先走k步遍历子树v回到u,在从u走j-k-2步到其他子树,不回到u
    dp[u][j][0]=max(dp[u][j][0],dp[v][k][1]+dp[u][j-k-2][0])

参考:http://www.cnblogs.com/wuyiqi/archive/2012/01/09/2316758.html

 #include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
using namespace std;
const int maxn = ;
const int maxk = ;
const int INF = 0x3f3f3f3f;
int dp[maxn][maxk][];//dp[i][j][0]表示从结点i走j步不会到i时的最大值,dp[i][j][1]表示从结点i走j步回到结点i时最大值。
//回到结点u:从u出发,要回到u,需要多走两步u-v,v-u,分配给v子树k步,其他子树j-k步,都返回:
//dp[u][j][1]=max(dp[u][j][1],dp[u][j-k-2][1]+dp[v][k][1])
//不回到结点u:先从其他子树回到u,再在子树v走k步,不回到u
//dp[u][j][0]=max(dp[u][j][0],dp[u][j-k-1][1]+dp[v][k][0])
//或者先走k步遍历子树v回到u,在从u走j-k-2步到其他子树,不回到u
//dp[u][j][0]=max(dp[u][j][0],dp[v][k][1]+dp[u][j-k-2][0])
int Head[maxn],totedge;
struct edge
{
int from, to, next;
edge(int ff=,int tt=,int nn=):from(ff),to(tt),next(nn){ }
}Edge[*maxn]; int N,K;
bool vis[maxn];
int val[maxn]; void AddEdge(int from, int to)
{
Edge[++totedge] = edge(from, to, Head[from]);
Head[from] = totedge;
Edge[++totedge] = edge(to, from, Head[to]);
Head[to] = totedge;
} void Init()
{
memset(dp, , sizeof(dp));
memset(Head, -, sizeof(Head));
memset(vis, , sizeof(vis));
totedge = ;
} void DP(int now)
{
vis[now] = true;
for (int u = Head[now]; u != -; u = Edge[u].next)
{
int v = Edge[u].to;
if (vis[v]) continue;
DP(v);
for (int j = K; j >= ; j--)
{
for (int k = ; k <= j; k++)
{
if (j - k - >= )
{
dp[now][j][] = max(dp[now][j][], dp[now][j - k - ][] + dp[v][k][]);
dp[now][j][] = max(dp[now][j][], dp[v][k][] + dp[now][j - k - ][]);
}
if (j - k - >= ) dp[now][j][] = max(dp[now][j][], dp[now][j - k - ][] + dp[v][k][]);
}
} }
}
int main()
{
while (~scanf("%d%d", &N, &K))
{
Init();
for (int i = ; i <= N; i++)
{
scanf("%d", val+i);
//dp[i][0][0] = dp[i][0][1] = val[i];
for (int j = ; j <= K; j++) dp[i][j][] = dp[i][j][] = val[i];
}
for (int i = ; i < N; i++)
{
int u, v;
scanf("%d%d", &u, &v);
AddEdge(u, v);
}
DP();
//int ans = 0;
//for (int i = 0; i <= K; i++)
//{
// ans = max(ans, max(dp[1][i][0], dp[1][i][1]));
//}
printf("%d\n", max(dp[][K][],dp[][K][]));
}
return ;
}

3、poj 1947 Rebuilding Roads  

  题意:需要把一棵树拆出一个P结点的新子树,问需要的删除的最少边数为多少?

  思路:dp[i][j]表示以i为根的子树形成j个结点的新树需要删去的最少边数。刚开始时,dp[i][1]=以i为根的子树的子树个数(即i的孩子的个数),即当做删除所有孩子。然后,dp[now][mv] = min(dp[now][mv], dp[now][mv - k]-1 + dp[u][k]),表示当考虑其u孩子形成的子树时,需要dp[now][mv - k]-1,因为之前所有dp操作都没有涉及当前子树(即表示删除该子树),现在考虑该子树时需要把连接子树和父结点的边添加回去,即删除的边数-1。

 #include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std; int n, p;
const int maxn = ;
const int INF = 0x3f3f3f3f;
struct edge
{
int from, to, next;
edge(int ff=,int tt=,int nn=):from(ff),to(tt),next(nn){ }
}Edge[maxn*];
int Head[maxn], totedge;
int dp[maxn][maxn];//dp[i][j]表示以i为根的子树形成j个结点的新树需要删去的最少边数
bool vis[maxn]; void Init()
{
memset(dp,INF, sizeof(dp));
for (int i = ; i <= n; i++) dp[i][] = ;
memset(Head, -, sizeof(Head));
memset(Edge,, sizeof(Edge));
memset(vis, , sizeof(vis));
totedge = ;
} void addEdge(int from, int to)
{
Edge[++totedge] = edge(from, to, Head[from]);
Head[from] = totedge;
Edge[++totedge] = edge(to, from, Head[to]);
Head[to] = totedge;
} void DP(int now)
{
vis[now] = true; for (int i = Head[now]; i != -; i = Edge[i].next)
{
int u = Edge[i].to;
if (vis[u]) continue;
DP(u);
for (int mv = p; mv >= ; mv--)
{
for (int k = ; k < mv; k++)
{//枚举加该子树的结点数
dp[now][mv] = min(dp[now][mv], dp[now][mv - k]- + dp[u][k]);//因为之前并没有添加该子树,所以删除的边数-1,表示添加该子树
}
}
}
}
int main()
{
while (~scanf("%d%d", &n, &p))
{
Init();
for (int i = ; i < n; i++)
{
int from, to;
scanf("%d%d", &from, &to);
addEdge(from, to);
dp[from][]++;
}
DP();//假设1为根结点
int ans = INF;
for (int i = ; i <= n; i++)
{
if(i==)ans = min(ans, dp[i][p]);
else ans = min(ans, dp[i][p] + );//如果非根节点,因为还要删去和父亲所连接的一条边,+1
}
printf("%d\n", ans);
}
return ;
}

DP专题·四(树形dp)的更多相关文章

  1. DP专题之概率DP

    注意:在概率DP中求期望要逆着推,求概率要正着推 概率DP求期望: 链接: http://acm.hdu.edu.cn/showproblem.php?pid=4405 dp[ i ]表示从i点走到n ...

  2. 树形dp专题总结

    树形dp专题总结 大力dp的练习与晋升 原题均可以在网址上找到 技巧总结 1.换根大法 2.状态定义应只考虑考虑影响的关系 3.数据结构与dp的合理结合(T11) 4.抽直径解决求最长链的许多类问题( ...

  3. 树形$dp$学习笔记

    今天学习了树形\(dp\),一开始浏览各大\(blog\),发现都\(TM\)是题,连个入门的\(blog\)都没有,体验极差.所以我立志要写一篇可以让初学树形\(dp\)的童鞋快速入门. 树形\(d ...

  4. hdu1011 Starship Troopers 树形DP

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1011 思路:很明显的树形背包 定义dp[root][m]表示以root为根,派m个士兵的最优解,那么d ...

  5. HDU 2196.Computer 树形dp 树的直径

    Computer Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Su ...

  6. 树形dp 入门

    今天学了树形dp,发现树形dp就是入门难一些,于是好心的我便立志要发一篇树形dp入门的博客了. 树形dp的概念什么的,相信大家都已经明白,这里就不再多说.直接上例题. 一.常规树形DP P1352 没 ...

  7. 树形动态规划(树形DP)入门问题—初探 & 训练

    树形DP入门 poj 2342 Anniversary party   先来个题入门一下~ 题意: 某公司要举办一次晚会,但是为了使得晚会的气氛更加活跃,每个参加晚会的人都不希望在晚会中见到他的直接上 ...

  8. 二叉苹果树|codevs5565|luoguP2015|树形DP|Elena

    二叉苹果树 题目描述 有一棵苹果树,如果树枝有分叉,一定是分2叉(就是说没有只有1个儿子的结点) 这棵树共有N个结点(叶子点或者树枝分叉点),编号为1-N,树根编号一定是1. 我们用一根树枝两端连接的 ...

  9. 树形DP总结,持续更新

    自己做了动态规划的题目已经有了一个月,但是成效甚微,所以来总结一下动态规划,希望自己能够温故知新.这个博客是关于树形dp的,动态规划的一类题目. 首先从最简单的树形DP入手,树形DP顾名思义就是一棵树 ...

随机推荐

  1. shell编程sed笔记

    源文件的内容 <modules> <module name="provider"> <!--发布模式--> <bds_mode/> ...

  2. 简单的SpringCloud 熔断Hystrix

    pom配置 <dependency> <groupId>org.springframework.cloud</groupId> <artifactId> ...

  3. 使用Selectivizr让你的 CSS3选择器 通吃IE6/7/8

    说到HTML5,总是会让人不自觉的想到CSS3,貌似他们就应该是成双成对.OK!前几天和大家分享了<使用html5shiv让HTML5通吃IE6/7/8>,那今天,便再和大家分享一个能让H ...

  4. [Idea Fragments] PostScript for 3D Print??

    今天看到一篇关于PostScript的文章<编程珠玑番外篇-P PostScript 语言里的珠玑>,尤其是篇尾的这段话,让我对3D Print浮想联翩: 因为 PostScript 语言 ...

  5. jquery mobile demo

    <!DOCTYPE html> <html> <head> <title>jQuery Mobile Demo</title> <me ...

  6. python import错误 SyntaxError: invalid syntax

    导入一个叫service-listener.py的文件是一直遇到错误: SyntaxError: invalid syntax 单独运行service-listener这个文件时,没有问题,只是不能被 ...

  7. 边缘检测sobel算子

    sobel算子 - sophia_hxw - 博客园http://www.cnblogs.com/sophia-hxw/p/6088035.html #1,个人理解 网上查了很多资料,都说sobel算 ...

  8. python入门(五):面向对象

    面向对象术语 类(Class): 用来描述具有相同的属性和方法的对象的集合.它定义了该集合中每个对象所共有的属性和方法.对象是类的实例. 类变量:类变量在整个实例化的对象中是公用的.类变量定义在类中且 ...

  9. python bottle学习(三)动态路由配置(通配符)

    from bottle import (run, route, get, post, default_app, Bottle) @route('/', method='GET') @route('/i ...

  10. 洛谷oj U3936(分成回文串) 邀请码:a0c9

    题目链接:传送门 题目大意:略 题目思路:DP 先预处理,分别以每个字母为中心处理能形成的回文串,再以两个字母为中心处理能形成的回文串. 然后 dp[i] 表示1~i 能形成的数目最少的回文串. 转移 ...