其实很早之前就学过树形dp,今天总接一下。树形dp就是一个在树上跑的dp(滑稽)

先是一道板子题:树上最大独立集

直接上代码了。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
struct node
{
int x,y,next;
};
node a[];
int len,last[];
void add(int x,int y)
{
a[++len].x = x;
a[len].y = y;
a[len].next = last[x];
last[x] = len;
}
int fa[],son[];
int f[][];
int v[];
/*
f[i][1]代表请i的最大值
f[i][0]代表不请i的最大值
*/
template <class T>
void read(T &x)
{
char c;
int op = ;
while(c = getchar(),c > '' || c < '')
if(c == '-') op = ;
x = c - '';
while(c = getchar(),c >= '' && c <= '')
x = x * + c - '';
if(op == )
x = -x;
}
void treedp(int x)
{
f[x][] = v[x];
for(int k = last[x];k;k = a[k].next) //相当于dfs
treedp(a[k].y);
for(int k = last[x];k;k = a[k].next)
{
int y = a[k].y;
f[x][] += f[y][]; //dp转移式①
}
f[x][] = ;
for(int k = last[x];k;k = a[k].next)
{
int y = a[k].y;
f[x][] += max(f[y][],f[y][]);//dp转移式②
}
}
int main()
{
int n;
read(n);
memset(f,-,sizeof(f));
memset(fa,,sizeof(fa));
for(int i = ;i <= n;i++)
read(v[i]);
int xx,yy;len = ;
memset(last,,sizeof(last));
while(scanf("%d%d",&xx,&yy) != EOF)
{
if(xx == && yy == )
{
break;
}
add(yy,xx);
fa[xx] = yy; //找根节点
}
int root = ;
for(int i = ;i <= n;i++)
if(fa[i] == )
{
root = i;
break;
}
treedp(root);
printf("%d\n",max(f[root][],f[root][]));
return ;
}

然后还有几个稍微比这个难一点的题,比如:加分二叉树

【问题描述】
设一个有n个节点的二叉树的中序遍历为(l,,,…,n),其中数字1,,,…,n为节点编号。
每个节点都有一个分数(均为正整数),记第i个节点的分数为di, 每棵子树都有一个加分,任一棵子树subtree的加分计算方法如下:
subtree的左子树的加分× subtree的右子树的加分+subtree的根的分数
若某个子树为空,规定其加分为1,叶子的加分就是叶节点本身的分数。不考虑它的空子树。
试求一棵符合中序遍历为(,,,…,n)且加分最高的二叉树tree。要求输出;
()tree的最高加分
()tree的前序遍历
【输入格式】
第1行:一个整数n(n<),为节点个数。
第2行:n个用空格隔开的整数,为每个节点的分数(分数<)。
【输出格式】
第1行:一个整数,为最高加分(结果不会超过2, )。
第2行:n个用空格隔开的整数,为该树的前序遍历。
【样例输入】 【样例输出】

这个题需要枚举中间的断点,然后进行dp。dp比之前简单了,但是其他的要难一些。

#include<cstdio>
#include<iostream>
using namespace std;
int root[][],d[],f[][];
void pre_visit(int l,int r)
{
if(l <= r)
{
cout<<root[l][r]<<" ";
pre_visit(l,root[l][r] - );
pre_visit(root[l][r] + , r);
}
}
int main()
{
int m;
cin>>m;
for(int i = ;i <= m;i++)
{
for(int j = ;j <= m;j++)
{
f[i][j] = ;
}
}
for(int i = ;i <= m;i++)
{
cin>>d[i];
root[i][i] = i;
f[i][i] = d[i];
}
for(int k = ;k <= m;k++)
{
for(int l = ;l <= m - k + ;l++)
{
int r = l + k - ;
for(int i = l;i <= r;i++)
{
if(f[l][r] < f[l][i - ] * f[i + ][r] + d[i])
{
root[l][r] = i;
f[l][r] = f[l][i - ] * f[i + ][r] + d[i];
}
}
}
}
cout<<f[][m]<<endl;
cout<<root[][m]<<" ";
pre_visit(,root[][m] - );
pre_visit(root[][m] + ,m);
}

还有一个皇宫看守,和最大独立点集很像

【问题描述】
太平王世子事件后,陆小凤成了皇上特聘的御前一品侍卫。 皇宫以午门为起点,直到后宫嫔妃们的寝宫,呈一棵树的形状;有边直接相连的宫殿可以互相望见。大内保卫森严,三步一岗,五步一哨,每个宫殿都要有人全天候看守,在不同的宫殿安排看守所需的费用不同。 可是陆小凤手上的经费不足,无论如何也没法在每个宫殿都安置留守侍卫。 编程任务:帮助陆小凤布置侍卫,在看守全部宫殿的前提下,使得花费的经费最少。
【输入格式】
输入文件中数据表示一棵树,描述如下:
第1行 n,表示树中结点的数目。
第2行至第n+1行,每行描述每个宫殿结点信息,依次为:该宫殿结点标号i(<I<=N),在该宫殿安置侍卫所需的经费K,该点的儿子数M,接下来M个数,分别是这个节点的M个儿子的标号R1,R2,...,RM。对于一个n( < n<=)个结点的树,结点标号在1到n之间,且标号不重复。
【输出格式】
输出文件仅包含一个数,为所求的最少的经费。
输入样例: 输出样例:

这个题很好想。

#include<iostream>
#include<cstring>
using namespace std;
typedef long long ll;
struct node
{
ll x,y,next;
};
node a[];
ll v[],f[][];
ll last[],len = ;
bool bk[];
/*
i节点安全代表i节点和子树安全
不安全代表i节点不安全,但是子树安全
f[i][0]表示x点不放人,但是安全
f[i][1]表示x点不放人,不安全
f[i][2]表示x点放人,所以安全
f[i][3]表示x点放人,但是不安全,显然不成立
*/
void treedp(int x)
{
f[x][] = v[x];
f[x][] = ;f[x][] = ;
ll minn = ;
bool bkk = false;
for(int k = last[x];k;k = a[k].next)
{
ll y = a[k].y;
if(bk[y] == false)
{
bk[y] = true;
treedp(y);
minn = min(f[y][] - f[y][],minn);
f[x][] += min(f[y][],f[y][]);
if(f[y][] <= f[y][])
{
bkk = true;
}//一定选f[i][2]
f[x][] += f[y][];
f[x][] += min(f[y][],min(f[y][],f[y][]));
}
}
if(bkk == false)
{
f[x][] += minn;
}
}
void add(int x,int y)
{
a[++len].x = x;
a[len].y = y;
a[len].next = last[x];
last[x] = len;
}
int main()
{
ll n;
cin>>n;
memset(f,,sizeof(f));
for(int i = ;i <= n;i++)
{
ll x,m,k;
cin>>x>>k>>m;
v[x] = k;
for(int j = ;j <= m;j++)
{
ll y;
cin>>y;
add(x,y);
add(y,x);
}
}
ll root = ;
memset(bk,false,sizeof(bk));
bk[root] = true;
treedp(root);
cout<<min(f[root][],f[root][]);
return ;
}

树形dp初步的更多相关文章

  1. 洛谷P1122 最大子树和 树形DP初步

    小明对数学饱有兴趣,并且是个勤奋好学的学生,总是在课后留在教室向老师请教一些问题.一天他早晨骑车去上课,路上见到一个老伯正在修剪花花草草,顿时想到了一个有关修剪花卉的问题.于是当日课后,小明就向老师提 ...

  2. 『没有上司的舞会 树形DP』

    树形DP入门 有些时候,我们需要在树形结构上进行动态规划来求解最优解. 例如,给定一颗\(N\)个节点的树(通常是无根树,即有\(N-1\)条无向边),我们可以选择任意节点作为根节点从而定义出每一颗子 ...

  3. [提升性选讲] 树形DP进阶:一类非线性的树形DP问题(例题 BZOJ4403 BZOJ3167)

    转载请注明原文地址:http://www.cnblogs.com/LadyLex/p/7337179.html 树形DP是一种在树上进行的DP相对比较难的DP题型.由于状态的定义多种多样,因此解法也五 ...

  4. 树形dp(A - Anniversary party HDU - 1520 )

    题目链接:https://cn.vjudge.net/contest/277955#problem/A 题目大意:略 具体思路:刚开始接触树形dp,说一下我对这个题的初步理解吧,首先,我们从根节点开始 ...

  5. poj3417 LCA + 树形dp

    Network Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 4478   Accepted: 1292 Descripti ...

  6. COGS 2532. [HZOI 2016]树之美 树形dp

    可以发现这道题的数据范围有些奇怪,为毛n辣么大,而k只有10 我们从树形dp的角度来考虑这个问题. 如果我们设f[x][k]表示与x距离为k的点的数量,那么我们可以O(1)回答一个询问 可是这样的话d ...

  7. 【BZOJ-4726】Sabota? 树形DP

    4726: [POI2017]Sabota? Time Limit: 20 Sec  Memory Limit: 128 MBSec  Special JudgeSubmit: 128  Solved ...

  8. 树形DP+DFS序+树状数组 HDOJ 5293 Tree chain problem(树链问题)

    题目链接 题意: 有n个点的一棵树.其中树上有m条已知的链,每条链有一个权值.从中选出任意个不相交的链使得链的权值和最大. 思路: 树形DP.设dp[i]表示i的子树下的最优权值和,sum[i]表示不 ...

  9. 树形DP

    切题ing!!!!! HDU  2196 Anniversary party 经典树形DP,以前写的太搓了,终于学会简单写法了.... #include <iostream> #inclu ...

随机推荐

  1. C# winform启动外部exe后,如何完全阻断父界面接收事件,扩展waitforexit

    公司的系统搭载了好多奇奇怪怪的exe,以前启动exe后,系统还能接着操作.但是后面又提出额外的需求,说是打开外部exe之后,启动exe的父界面要完全不能进行任何操作.当然按常人所想再加一句waitfo ...

  2. csf 课件转化为wmv正常格式

    1. 下载csf文件到本地:如下图 2.从下面百度网盘下载到本地: https://pan.baidu.com/s/1BBbgq  n85a 3.安装并出现下面图标,点击打开 4. 运行如下图 5.  ...

  3. 重现apache commons fileupload DOS漏洞

    这个漏洞是2014年2月4日被发现的, 因为该组件试用范围非常广, 所以该漏洞的影响也非常巨大.通过特制的包含畸形header的http请求,可以导致使用该组件的应用程序进入无限循环从而耗尽CPU等资 ...

  4. html5——2D转换

    transform 属性 1.向元素应用 2D 或 3D 转换 2.该属性允许我们对元素进行旋转.缩放.移动或倾斜. 缩放与位移 transform: scale(, 0.5);//水平缩放,垂直缩放 ...

  5. java_io学习_编码

    package io; public class encodingDemo{ public static void main(String[] args) throws Exception{ // T ...

  6. C# SetWindowsHookEx

    [DllImport("user32.dll")] static extern IntPtr SetWindowsHookEx(int idHook, keyboardHookPr ...

  7. Java对象的创建及使用

    Java对象的创建及使用 对象是类的具体实例(instance),是真实存在的个体:

  8. linux 头文件和库文件的设置

    GCC/G++会查找系统默认的include和link的路径,以及自己在编译命令中指定的路径.自己指定的路径就不说了,这里说明一下系统自动搜索的路径. [1]include头文件路径 除了默认的/us ...

  9. PAT 1118 Birds in Forest

    Some scientists took pictures of thousands of birds in a forest. Assume that all the birds appear in ...

  10. 338. Counting Bits(动态规划)

    Given a non negative integer number num. For every numbers i in the range 0 ≤ i ≤ num calculate the ...