最近几天学了一下树形\(dp\) 其实早就学过了 来提高一下打开树形\(dp\)的姿势。

1、没有上司的晚会

我的人生第一道树形\(dp\),其实就是两种情况:

\(dp[i][1]\)表示第i个人来时的最大人数

\(dp[i][0]\)表示第i个人不来时的最大人数

然后递归至叶子节点,倒推\(dp\)

状态转移方程:

\[dp[root][1]+=dp[G[root][i]][0];
\]

\[dp[root][0]+=max(dp[G[root][i]][1],dp[G[root][i]][0]);
\]

\(Code\ Below:\)

#pragma GCC optimize(2)
#include <bits/stdc++.h>
using namespace std;
int n;
int f[6010];
int dp[6010][2];
vector<int> G[6010];
//dp[i][1]表示第i个人来
//dp[i][0]表示第i个人不来 void dfs(int root)
{
for(int i=0;i<G[root].size();i++){
dfs(G[root][i]);
}
for(int i=0;i<G[root].size();i++){
dp[root][1]+=dp[G[root][i]][0];
dp[root][0]+=max(dp[G[root][i]][1],dp[G[root][i]][0]);
}
} int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&dp[i][1]);
dp[i][0]=0;f[i]=i;
}
int u,v;
while(1){
scanf("%d%d",&u,&v);
if(!u&&!v) break;
f[u]=v;
G[v].push_back(u);
}
int root=1;
while(root!=f[root])
root=f[root];
dfs(root);
printf("%d\n",max(dp[root][1],dp[root][0]));
return 0;
}

2、二叉苹果树

水题

有三种情况:

1、只剪左儿子

2、只剪右儿子

3、左儿子和右儿子都剪一点

然后枚举每个节点剪几条树枝,就水过了

\(Code\ Below:\)

#include <bits/stdc++.h>
#define maxn 110
using namespace std;
int f[maxn][maxn],vis[maxn];
int T[maxn][maxn],e[maxn][maxn],n,q; int dfs(int root,int m){
if(m==0) return 0;
if(f[root][m]) return f[root][m];
int ans=0,sum=0;
if(T[root][0]) sum=dfs(T[root][0],m-1)+e[root][T[root][0]];
ans=max(ans,sum);
if(T[root][1]) sum=dfs(T[root][1],m-1)+e[root][T[root][1]];
ans=max(ans,sum);
for(int j=1;j<m;j++){
sum=0;
if(T[root][0]) sum+=dfs(T[root][0],j-1)+e[root][T[root][0]];
if(T[root][1]) sum+=dfs(T[root][1],m-j-1)+e[root][T[root][1]];
ans=max(ans,sum);
}
f[root][m]=ans;
return ans;
}
int main()
{
scanf("%d%d",&n,&q);
vis[1]=1;
for(int i=1;i<n;i++){
int x,y,w;
scanf("%d%d%d",&x,&y,&w);
if(vis[y]) swap(x,y);
e[x][y]=w;vis[y]=1;
if(T[x][0]) T[x][1]=y;
else T[x][0]=y;
}
printf("%d\n",dfs(1,q));
return 0;
}

3、战略游戏

同没有上司的晚会,就是把\(max\)改成\(min\)

\(Code\ Below:\)

#include <bits/stdc++.h>
#define maxn 1510
using namespace std;
vector<int> T[maxn];
int n,dp[maxn][2],f[maxn]; void dfs(int root){
for(int i=0;i<T[root].size();i++)
dfs(T[root][i]);
for(int i=0;i<T[root].size();i++){
dp[root][1]+=min(dp[T[root][i]][0],dp[T[root][i]][1]);
dp[root][0]+=dp[T[root][i]][1];
}
} int main()
{
scanf("%d",&n);
for(int i=0;i<n;i++){
f[i]=i;
dp[i][1]=1;
dp[i][0]=0;
}
for(int i=0;i<n;i++){
int m,k;
scanf("%d%d",&m,&k);
for(int j=0;j<k;j++){
int son;
scanf("%d",&son);
T[m].push_back(son);
f[son]=m;
}
}
int root=0;
while(root!=f[root])
root=f[root];
dfs(root);
printf("%d\n",min(dp[root][0],dp[root][1]));
return 0;
}

4、“访问”美术馆

蛋疼的输入

输入完就\(dp\),其实可以叫做记搜吧,枚举到每个画廊的所有时间

\(Code\ Below:\)

#include <bits/stdc++.h>
#define maxn 1010
using namespace std;
int dp[maxn][maxn];
struct T{
int cost,val;
}T[maxn<<2];
int Time; void Init(int now){
scanf("%d%d",&T[now].cost,&T[now].val);
T[now].cost<<=1;
if(!T[now].val){
Init(now<<1);Init(now<<1|1);
}
} int dfs(int x,int tot){
if(dp[x][tot]||!tot) return dp[x][tot];
if(T[x].val) return dp[x][tot]=min(T[x].val,(tot-T[x].cost)/5);
for(int i=0;i<=tot-T[x].cost;i++)
dp[x][tot]=max(dp[x][tot],dfs(x<<1,i)+dfs(x<<1|1,tot-T[x].cost-i));
return dp[x][tot];
} int main()
{
scanf("%d",&Time);
Time--;
Init(1);
printf("%d",dfs(1,Time));
return 0;
}

5、vacation

水题

\(Code\ Below:\)

#include <bits/stdc++.h>
using namespace std;
const int maxn=50000+10;
int n,dp[maxn][2];
vector<int> tree[maxn]; void dfs(int x,int fa)
{
for(int i=0;i<tree[x].size();i++)
if(tree[x][i]!=fa)
dfs(tree[x][i],x);
dp[x][1]=1;
for(int i=0;i<tree[x].size();i++){
if(tree[x][i]==fa) continue;
dp[x][0]+=max(dp[tree[x][i]][0],dp[tree[x][i]][1]);
dp[x][1]+=dp[tree[x][i]][0];
}
} int main()
{
scanf("%d",&n);
int x,y;
for(int i=1;i<n;i++){
scanf("%d%d",&x,&y);
tree[x].push_back(y);
tree[y].push_back(x);
}
dfs(1,0);
printf("%d\n",max(dp[1][0],dp[1][1]));
return 0;
}

6、gather

\(hzwer\)的博客讲的比我好

其实就是换根,推理过程已注释

\(Code\ Below:\)

#include <bits/stdc++.h>
#define ll long long
#define INF 1000000000000000
using namespace std;
const ll maxn=100000+10;
ll n,head[maxn],siz[maxn],tot,sum,ans;
/*
ans'=ans+(sum-siz[e[i].to])*e[i].val-siz[e[i].to]*e[i].val
=>ans'=ans+(sum-2*siz[e[i].to])*e[i].val;
(sum-2*siz[e[i].to]<0)ans=>ans'
*/
struct node{
ll to,next,val;
}e[maxn<<1]; inline void add(ll x,ll y,ll w){
e[++tot].to=y;
e[tot].val=w;
e[tot].next=head[x];
head[x]=tot;
} void dfs(ll x,ll fa,ll dis)
{
ans+=dis*siz[x];
for(ll i=head[x];i;i=e[i].next){
ll y=e[i].to;
if(y==fa) continue;
dfs(y,x,dis+e[i].val);
siz[x]+=siz[y];
}
} void solve(ll x,ll fa){
for(ll i=head[x];i;i=e[i].next){
ll y=e[i].to;
if(y==fa) continue;
if(sum-2*siz[y]<0) {
ans+=(sum-2*siz[y])*e[i].val;
solve(y,x);
}
}
} int main()
{
scanf("%lld",&n);
ll x,y,w;
for(ll i=1;i<=n;i++){
scanf("%lld",&siz[i]);
sum+=siz[i];
}
for(ll i=1;i<n;i++){
scanf("%lld%lld%lld",&x,&y,&w);
add(x,y,w);add(y,x,w);
}
dfs(1,0,0);solve(1,0);
printf("%lld\n",ans);
return 0;
}

7、Barn Painting

手动写\(if\)判断,然后统计\(dfs\)一下,记录\(sum\),乘一下

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const ll maxn=100000+10;
const ll p=1e9+7;
ll n,k,head[maxn],to[maxn<<1],nxt[maxn<<1],vis[maxn],tot,ans;ll dp[maxn][3]; inline void add(ll x,ll y){
to[++tot]=y;
nxt[tot]=head[x];
head[x]=tot;
} ll dfs(ll x,ll col,ll fa)
{
ll acol,bcol;
if(col==0) acol=1,bcol=2;
if(col==1) acol=0,bcol=2;
if(col==2) acol=0,bcol=1;
if(vis[x]!=-1&&vis[x]!=col) return dp[x][col]=0;
if(dp[x][col]>=0) return dp[x][col];
dp[x][col]=1;
for(ll i=head[x];i;i=nxt[i]){
ll y=to[i];
if(y==fa) continue;
ll sum=0;
sum=(sum+dfs(y,acol,x))%p;
sum=(sum+dfs(y,bcol,x))%p;
dp[x][col]=(dp[x][col]*sum)%p;
}
return dp[x][col];
} int main()
{
memset(vis,-1,sizeof(vis));
memset(dp,-1,sizeof(dp));
scanf("%lld%lld",&n,&k);
ll x,y;
for(ll i=1;i<n;i++){
scanf("%lld%lld",&x,&y);
add(x,y);add(y,x);
}
for(ll i=1;i<=k;i++){
scanf("%lld%lld",&x,&y);
vis[x]=--y;
}
for(ll i=0;i<3;i++)
dfs(1,i,1);
for(ll i=0;i<3;i++)
ans=(ans+dp[1][i])%p;
printf("%lld\n",ans);
return 0;
}

[学习笔记]树形dp的更多相关文章

  1. [学习笔记] 数位DP的dfs写法

    跟着洛谷日报走,算法习题全都有! 嗯,没错,这次我也是看了洛谷日报的第84期才学会这种算法的,也感谢Mathison大佬,素不相识,却写了一长篇文章来帮助我学习这个算法. 算法思路: 感觉dfs版的数 ...

  2. [学习笔记]区间dp

    区间 \(dp\) 1.[HAOI2008]玩具取名 \(f[l][r][W/I/N/G]\) 表示区间 \([l,r]\) 中能否压缩成 \(W/I/N/G\) \(Code\ Below:\) # ...

  3. [学习笔记]插头dp

    基于连通性的状压dp 巧妙之处:插头已经可以表示内部所有状态了. 就是讨论麻烦一些. 简介 转移方法:逐格转移,分类讨论 记录状态方法:最小表示法(每次要重新编号,对于一类没用“回路路径”之类的题,可 ...

  4. 【学习笔记】dp基础

    知识储备:dp入门. 好了,完成了dp入门,我们可以做一些稍微不是那么裸的题了. dp基础,主要是做题,只有练习才能彻底掌握. 洛谷P1417 烹调方案 分析:由于时间的先后会对结果有影响,所以c[i ...

  5. 【学习笔记】dp入门

    知识点 动态规划(简称dp),可以说是各种程序设计中遇到的第一个坎吧,这篇博文是我对dp的一点点理解,希望可以帮助更多人dp入门.   先看看这段话 动态规划(dynamic programming) ...

  6. 笔记-树形dp

    this is not a 正经的note you may not understand Problem 1:二叉树,有权,要选它父亲才能选它,$n\leq200,m\leq500$ I: $dp_{ ...

  7. [学习笔记]动态dp

    其实就过了模板. 感觉就是带修改的dp [模板]动态dp 给定一棵n个点的树,点带点权. 有m次操作,每次操作给定x,y表示修改点x的权值为y. 你需要在每次操作之后求出这棵树的最大权独立集的权值大小 ...

  8. [学习笔记]整体DP

    问题: 有一些问题,通常见于二维的DP,另一维记录当前x的信息,但是这一维过大无法开下,O(nm)也无法通过. 但是如果发现,对于x,在第二维的一些区间内,取值都是相同的,并且这样的区间是有限个,就可 ...

  9. [BZOJ4011][HNOI2015] 落忆枫音(学习笔记) - 拓扑+DP

    其实就是贴一下防止自己忘了,毕竟看了题解才做出来 Orz PoPoQQQ 原文链接 Description 背景太长了 给定一个DAG,和一对点(x, y), 在DAG中由x到y连一条有向边,求生成树 ...

随机推荐

  1. 2019.01.02 NOIP训练 三七二十一(生成函数)

    传送门 生成函数基础题. 题意简述:求由1,3,5,7,9这5个数字组成的n位数个数,要求其中3和7出现的次数都要是偶数. 考虑对于每个数字构造生成函数. 对于1,5,9:∑nxnn!=ex\sum_ ...

  2. c# 文件笔记

    1.文件属性操作 File类与FileInfo都能实现.静态方法与实例化方法的区别! //use File class Console.WriteLine(File.GetAttributes(fil ...

  3. UVa 10163 Storage Keepers (二分 + DP)

    题意:有n个仓库,m个管理员,每个管理员有一个能力值P,每个仓库只能由一个管理员看管,但是每个管理员可以看管k个仓库(但是这个仓库分配到的安全值只有p/k,k=0,1,...),雇用的管理员的工资即为 ...

  4. HDU 5663 Hillan and the girl (莫比乌斯反演 + 分块)

    题意:给定n,m,求,其中F(x)=0,,如果x是完全平方数,否则是1. 析: 由于按照题意的F,不好筛选,所以我们反过来,F(x),x是平方数,就是1,否则是0. 这个是可以预处理出来的,可以用筛选 ...

  5. DocumentFragment类型

    nodeType 11 nodeName #document-fragment nodeValue NULL parentNode null createdocumentfragment()方法创建了 ...

  6. [置顶] AngularJS实战之路由ui-sref-active使用

    当我们使用angularjs的路由时,时常会出现一个需求,当选中菜单时把当前菜单的样式设置为选中状态(多数就是改变颜色) 接下来就看看Angular-UI-Router里的指令ui-sref-acti ...

  7. 强大的DataGrid组件[1]

    说明:DataGrid组件是Silverlight数据组件中最为常用并且是功能最为强大的数据组件.因此,对开发者而言,深入了解其特性是十分有必要的.本文先介绍该组件的基本特性,接着通过几个简单实例来说 ...

  8. Python 之 filecmp

    Python 之 filecmp 2017年7月12日 参考书籍:<Python自动化运维 ——技术与最佳实践> 作者:李天斯 1.什么是filecmp filecmp作为python的标 ...

  9. HP 集群软件 - 不能接收节点的设备查询信息:软件引起的连接失败

    问题 # cmcheckconf -v -C /etc/cmcluster/cmclconfig.ascii Begin cluster verification...  Checking clust ...

  10. info AI drive

    Who we look for Here at comma, we don't care about the source of your education or your traditional ...