YBT 5.2 树形动态规划
题解在代码中
二叉苹果树[loj 10153]
/*
若要留q条边便是要留q+1个点
所以记忆化搜索
dp[pos][ans]=max(dp[pos][ans],dp[l[pos]][k]+dp[r[pos]][ans-k-1]+a[pos])
0<=k<=ans-1
*/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
inline int read()
{
int f=,ans=;char c;
while(c<''||c>''){if(c=='-')f=-;c=getchar();}
while(c>=''&&c<=''){ans=ans*+c-'';c=getchar();}
return ans*f;
}
int n,q;
int book[][],a[],l[],r[];
void dfs(int pos){
for(int i=;i<=n;i++)
{
if(book[pos][i]!=-)
{
a[i]=book[pos][i];
book[pos][i]=-;book[i][pos]=-;
l[pos]=i;
dfs(i);
break;
}
}
for(int i=;i<=n;i++)
{
if(book[pos][i]!=-)
{
a[i]=book[pos][i];
book[pos][i]=-;book[i][pos]=-;
r[pos]=i;
dfs(i);
break;
}
}
return;
}
int dp[][];
int solve(int pos,int ans)
{
if(ans==) return ;
if(dp[pos][ans]!=-) return dp[pos][ans];
if(r[pos]==&&l[pos]==) return a[pos];
for(int j=;j<=ans-;j++)
dp[pos][ans]=max(dp[pos][ans],solve(l[pos],j)+solve(r[pos],ans--j)+a[pos]);
return dp[pos][ans]; }
int main()
{
memset(dp,-,sizeof(dp));
memset(book,-,sizeof(book));
n=read(),q=read();
for(int i=;i<n;i++)
{
int u=read(),v=read(),w=read();book[u][v]=w;book[v][u]=w;
}
dfs();
cout<<solve(,q+);
}
选课[loj 10154]
/*
建立一个虚根0使得将森林转化成为树
dp[i][j]表示为以i为根的子树下最多选j门课的最大学分
dfs后先进行背包处理
这是先不考虑先修课
再将有先修课 (pos!=0)时dp的容积为容积-1的最大值加上选修此门课的积分
dp[i][j]=max(dp[i][j],dp[i][j-k]+dp[son][k])
j (m~0)
k(j~0)
*/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
inline int read()
{
int f=,ans=;char c;
while(c<''||c>''){if(c=='-')f=-;c=getchar();}
while(c>=''&&c<=''){ans=ans*+c-'';c=getchar();}
return ans*f;
}
int n,m;
struct node{
int u,v,nex;
}x[];
int s[];
int t,cnt;
int dp[][],head[];
void add(int u,int v)
{
x[cnt].u=u,x[cnt].v=v,x[cnt].nex=head[u],head[u]=cnt++;
}
void dfs(int pos)
{
for(int p=head[pos];p!=-;p=x[p].nex)
{
int xx=x[p].v;
dfs(xx);
for(int i=m;i>=;i--)
for(int j=i;j>=;j--) dp[pos][i]=max(dp[pos][i],dp[pos][i-j]+dp[xx][j]);
}
if(pos!=)
{
for(int i=m;i>=;i--) dp[pos][i]=dp[pos][i-]+s[pos];
} // for(int i=m;i>=0;i--) cout<<"位置:"<<pos<<" 选课:"<<i<<" dp:"<<dp[pos][i]<<endl;
// system("pause");
return ;
}
int main()
{
memset(head,-,sizeof(head));
n=read(),m=read();
for(int i=;i<=n;i++)
{
t=read(),s[i]=read();
add(t,i);
}
dfs();
cout<<dp[][m];
}
数字转换[loj 10155]
/*
先预处理好因数和,再建一棵树
求树的最长链即可
*/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#pragma GCC optimize(2)
using namespace std;
inline long long read()
{
long long f=,ans=;char c;
while(c<''||c>''){if(c=='-')f=-;c=getchar();}
while(c>=''&&c<=''){ans=ans*+c-'';c=getchar();}
return ans*f;
}
long long n,cnt;
struct node{
long long u,v,nex;
}x[];
long long head[];
long long dp1[],dp2[];
void add(long long u,long long v)
{
x[cnt].u=u,x[cnt].v=v,x[cnt].nex=head[u],head[u]=cnt++;
}
long long sum[];
long long maxn,book[];
//dp1表示最长,dp2表次长
void dfs(long long pos)
{
// cout<<pos<<endl;
for(long long i=head[pos];i!=-;i=x[i].nex)
{
long long p=x[i].v;
if(book[p]==)
{
book[p]=;
dfs(p);
if(dp1[p]+>dp1[pos]) dp2[pos]=dp1[pos],dp1[pos]=dp1[p]+;
else if(dp1[p]+>dp2[pos]) dp2[pos]=dp1[p]+;
maxn=max(maxn,dp1[pos]+dp2[pos]);
}
}
}
int main()
{
memset(head,-,sizeof(head));
n=read();
for(int i=;i<=n/;i++)
{
for(int j=i*;j<=n;j+=i)
{
sum[j]+=i;
}
}
for(int i=;i<=n;i++)
if(sum[i]<i) add(sum[i],i),add(i,sum[i]);
book[]=;
dfs();
cout<<maxn;
}
战略游戏[loj 10156]
/*
0为不选,1为选
pos的子孙为x
dp[pos][0]=sum(dp[x][1])
dp[pos][1]=sum(min(dp[x][0],dp[x][1]));
*/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
inline int read()
{
int f=,ans=;char c;
while(c<''||c>''){if(c=='-')f=-;c=getchar();}
while(c>=''&&c<=''){ans=ans*+c-'';c=getchar();}
return ans*f;
}
struct node{
int u,v,nex;
}x[];
int head[],n,cnt,dp[][],book[];
void add(int u,int v)
{
x[cnt].u=u,x[cnt].v=v,x[cnt].nex=head[u],head[u]=cnt++;
}
void dfs(int pos)
{
// cout<<pos<<endl;
dp[pos][]=;
for(int i=head[pos];i!=-;i=x[i].nex)
{
int p=x[i].v;
if(book[p]==)
{
book[p]=;
dfs(p);
dp[pos][]+=dp[p][];
dp[pos][]+=min(dp[p][],dp[p][]);
// cout<<pos<<" "<<dp[pos][0]<<" "<<dp[pos][1]<<" "<<endl;
}
}
}
int main()
{
memset(head,-,sizeof(head));
n=read();
for(int i=;i<=n;i++)
{
int t=read(),k=read();
for(int j=;j<=k;j++)
{
int p=read();
add(t,p),add(p,t);
}
}
book[]=;
dfs();
cout<<min(dp[][],dp[][]);
}
皇宫看守[loj 10157]
/*
dp[pos][0]为pos自己安放
dp[pos][1]为pos被自己的父亲看到
dp[pos][2]为pos被自己的子孙看到 dp[pos][0]+=min(dp[x][0],dp[x][1],dp[x][2])
dp[pos][1]+=min(dp[x][0],dp[x][2])
dp[pos][2]+=min(dp[x][0],dp[x][2])
dp[pos][2]+=k,dp[pos][0]+=s[pos]
k=min(k,dp[pos][0]-min(dp[pos][0],dp[pos][2]));
*/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
inline int read()
{
int f=,ans=;char c;
while(c<''||c>''){if(c=='-')f=-;c=getchar();}
while(c>=''&&c<=''){ans=ans*+c-'';c=getchar();}
return ans*f;
}
int dp[][];
struct node{
int u,v,nex;
}x[];
int s[];
int a[],cnt,n;
int head[];
void add(int u,int v)
{
x[cnt].u=u,x[cnt].v=v,x[cnt].nex=head[u],head[u]=cnt++;
}
int dfs(int pos,int fath)
{
int k=;
for(int i=head[pos];i!=-;i=x[i].nex)
{
int p=x[i].v;
if(p==fath) continue;
dfs(p,pos);
dp[pos][]+=min(min(dp[p][],dp[p][]),dp[p][]);
dp[pos][]+=min(dp[p][],dp[p][]);
dp[pos][]+=min(dp[p][],dp[p][]);
k=min(k,dp[p][]-min(dp[p][],dp[p][]));
}
dp[pos][]+=s[pos];
dp[pos][]+=k;
}
int main()
{
memset(head,-,sizeof(head));
n=read();
for(int i=;i<=n;i++)
{
int xx=read();
s[xx]=read();
int m=read();
for(int j=;j<=m;j++)
{
int p=read();
// cout<<xx<<" "<<p<<endl;
add(xx,p);
add(p,xx);
}
}
dfs(,);
cout<<min(dp[][],dp[][]);
}
加分二叉树[loj 10158]
/*
中序遍历
左子树——根——右子树
每次枚举根
进行记忆化dfs
将last存放最优根
*/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
inline int read()
{
int f=,ans=;char c;
while(c<''||c>''){if(c=='-')f=-;c=getchar();}
while(c>=''&&c<=''){ans=ans*+c-'';c=getchar();}
return ans*f;
}
int dp[][],s[],n,last[][];
int dfs(int l,int r)
{
// cout<<l<<" "<<r<<endl;
if(l==r) return s[l];
if(l>r) return ;
if(dp[l][r]!=-) return dp[l][r];
for(int i=l;i<=r;i++)
{
int p=dfs(l,i-)*dfs(i+,r)+s[i];
if(p>dp[l][r])
{
dp[l][r]=p;
last[l][r]=i;
}
}
return dp[l][r];
}
void sc(int l,int r)
{ if(l>r) return;
if(l==r)
{
cout<<l<<" ";
return;
}
cout<<last[l][r]<<" ";
sc(l,last[l][r]-);
sc(last[l][r]+,r);
return;
}
int main()
{
memset(dp,-,sizeof(dp));
n=read();
for(int i=;i<=n;i++) s[i]=read();
cout<<dfs(,n)<<endl;
// cout<<
sc(,n);
}
旅游规划[loj 10159]
/*
此题是找最长链上的所有店
dp1求子树上最长路径
dp2求子树上次长路径 两者相加便可以求出最长路径的长度 dp3记录除子树外的最长路径 */
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
inline int read()
{
int f=,ans=;char c;
while(c<''||c>''){if(c=='-')f=-;c=getchar();}
while(c>=''&&c<=''){ans=ans*+c-'';c=getchar();}
return ans*f;
}
struct node{
int u,v,nex;
}x[];
int n,cnt,head[];
int book[],dp3[],maxn,dp1[],dp2[];
void add(int u,int v)
{
x[cnt].u=u,x[cnt].v=v,x[cnt].nex=head[u],head[u]=cnt++;
}
void dfs(int pos)
{
// cout<<pos<<endl;
for(int i=head[pos];i!=-;i=x[i].nex)
{
int p=x[i].v;
// cout<<p<<endl;
if(book[p]==)
{
book[p]=;
dfs(p);
if(dp1[p]+>=dp1[pos])
{
dp2[pos]=dp1[pos];
dp1[pos]=dp1[p]+;
}
else if(dp1[p]+>=dp2[pos])
dp2[pos]=dp1[p]+;
maxn=max(maxn,dp1[pos]+dp2[pos]);
}
}
return;
}
void dfs1(int pos,int fath)
{
int sum=;
for(int i=head[pos];i!=-;i=x[i].nex)
if(x[i].v!=fath&&dp1[pos]==dp1[x[i].v]+) sum++;
for(int i=head[pos];i!=-;i=x[i].nex)
{
if(x[i].v!=fath)
{
if(dp1[x[i].v]+!=dp1[pos]) dp3[x[i].v]=max(dp1[pos],dp3[pos])+;
else if(dp1[x[i].v]+==dp1[pos]&&sum>)dp3[x[i].v]=max(dp1[pos],dp3[pos])+;
else dp3[x[i].v]=max(dp2[pos],dp3[pos])+;
dfs1(x[i].v,pos);
}
}
}
int main()
{
memset(head,-,sizeof(head));
n=read();
// for(int i=0;i<n;i++) f[i]=i;
for(int i=;i<n;i++)
{
int u=read(),v=read();
add(u,v),add(v,u);
}
book[]=;
dfs();
// cout<<maxn<<" ";
memset(book,,sizeof(book));
dfs1(,-);
for(int i=;i<n;i++)
if(dp1[i]+max(dp2[i],dp3[i])==maxn) cout<<i<<endl;
return ;
}
周年纪念晚会[loj 10160]
/*
0不选1选
*/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
inline int read()
{
int f=,ans=;char c;
while(c<''||c>''){if(c=='-')f=-;c=getchar();}
while(c>=''&&c<=''){ans=ans*+c-'';c=getchar();}
return ans*f;
}
int a[],n;
struct node{
int u,v,nex;
}x[];
int cnt;
int head[],dp[][],t[];
void add(int u,int v)
{
x[cnt].u=u,x[cnt].v=v,x[cnt].nex=head[u],head[u]=cnt++;
}
void dfs(int pos)
{
// cout<<pos<<endl;
dp[pos][]=;
dp[pos][]=a[pos];
for(int i=head[pos];i!=-;i=x[i].nex)
{
int p=x[i].v;
dfs(p);
dp[pos][]+=max(,max(dp[p][],dp[p][]));
dp[pos][]+=max(,dp[p][]); }
}
int main()
{
memset(head,-,sizeof(head));
n=read();
memset(dp,0xcf,sizeof(dp));
for(int i=;i<=n;i++) a[i]=read();
for(int i=;i<n;i++)
{
int u=read(),v=read();
add(v,u);t[u]=;
}
int sry=;
while(t[sry]==) sry++;
dfs(sry);
cout<<max(dp[sry][],dp[sry][]);
}
叶子的颜色[loj 10161]
/*
dp[pos][0]表示pos涂黑色
1 表示涂白色
2 表示不涂 dp[pos][0]+=min(dp[x][0]-1,dp[x][1],dp[x][2])
1,2同理 -1是因为此点就不需要涂 预处理见代码
*/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
inline int read()
{
int f=,ans=;char c;
while(c<''||c>''){if(c=='-')f=-;c=getchar();}
while(c>=''&&c<=''){ans=ans*+c-'';c=getchar();}
return f*ans;
}
int m,n,c[];
struct node{
int u,v,nex;
}x[];
int head[],cnt;
void add(int u,int v)
{
x[cnt].u=u,x[cnt].v=v,x[cnt].nex=head[u],head[u]=cnt++;
}
int book[],dp[][];
void dfs(int pos)
{
if(pos>=&&pos<=m)
{
dp[pos][c[pos]]=;
dp[pos][-c[pos]]=dp[pos][]=<<-;
}
else{
dp[pos][]=dp[pos][]=;
}
for(int i=head[pos];i!=-;i=x[i].nex)
{
int t=x[i].v;
if(book[t]==)
{
book[t]=;
dfs(t);
dp[pos][]+=min(dp[t][]-,min(dp[t][],dp[t][]));
dp[pos][]+=min(dp[t][]-,min(dp[t][],dp[t][]));
dp[pos][]+=min(dp[t][],min(dp[t][],dp[t][]));
}
}
}
int main()
{
memset(head,-,sizeof(head));
n=read(),m=read();
for(int i=;i<=m;i++) c[i]=read();
for(int i=;i<n;i++)
{
int u=read(),v=read();
add(u,v),add(v,u);
}
book[n]=;
dfs(n);
cout<<min(dp[n][],min(dp[n][],dp[n][]));
}
骑士[loj 10162]
/*
断环为链,与没有上司的舞会接下来的十分相似
*/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
inline long long read()
{
long long f=,ans=;char c;
while(c<''||c>''){if(c=='-')f=-;c=getchar();}
while(c>=''&&c<=''){ans=ans*+c-'';c=getchar();}
return f*ans;
}
struct node{
long long u,v,nex;
}x[];
long long cnt;
long long head[],n,s[],vis[],root,book[],uu,vv;
void add(long long u,long long v)
{
x[cnt].u=u,x[cnt].v=v,x[cnt].nex=head[u],head[u]=cnt++;
} bool flag;
long long ans;
void dfs(long long pos,long long fa)
{
for(long long i=head[pos];i!=-;i=x[i].nex)
{
long long p=x[i].v;
if(fa!=p)
{
if(vis[p]==)
{
vis[p]=;
dfs(p,pos);
}
else{
flag=true;
uu=pos,vv=p;
}
}
}
}
long long dp[][];//0没用,1用
long long inf=<<-;
void dfs_dp(long long pos,long long fa)
{
// cout<<pos<<endl;
dp[pos][]=s[pos];
for(long long i=head[pos];i!=-;i=x[i].nex)
{
long long p=x[i].v;
if(p!=fa)
{
if(p==-inf) continue;
dfs_dp(p,pos);
dp[pos][]+=max(dp[p][],dp[p][]);
dp[pos][]+=dp[p][];
}
}
return;
}
void work(long long pos)
{
memset(dp,,sizeof(dp));
flag=false;
vis[pos]=;
dfs(pos,-);
// cout<<uu<<" "<<vv<<endl;
if(flag==false)
{
dfs_dp(pos,-);
ans+=max(dp[pos][],dp[pos][]);
}
else if(flag==true)
{
long long maxn=;
for(long long i=head[uu];i!=-;i=x[i].nex)
{
long long p=x[i].v;
if(p==vv)
{
x[i].v=-inf;
break;
}
}
for(long long i=head[vv];i!=-;i=x[i].nex)
{
long long p=x[i].v;
if(p==uu)
{
x[i].v=-inf;
break;
}
}
// cout<<uu<<" "<<vv<<endl;
dfs_dp(uu,-);
// return ;
long long x1=dp[uu][];
// cout<<x1<<endl;
memset(dp,,sizeof(dp));
dfs_dp(vv,-);
long long x2=dp[vv][];
// cout<<x2<<endl;
maxn=max(x1,x2);
ans+=maxn;
}
}
int main(void)
{
memset(head,-,sizeof(head));
n=read();
for(long long i=;i<=n;i++)
{
s[i]=read();
long long p=read();
add(i,p),add(p,i);
}
for(long long i=;i<=n;i++)
{
if(vis[i]==)
{
work(i);
// return 0;
}
}
cout<<ans;
}
YBT 5.2 树形动态规划的更多相关文章
- 蓝桥杯 ALGO-4 结点选择 (树形动态规划)
问题描述 有一棵 n 个节点的树,树上每个节点都有一个正整数权值.如果一个点被选择了,那么在树上和它相邻的点都不能被选择.求选出的点的权值和最大是多少? 输入格式 第一行包含一个整数 n . 接下来的 ...
- 树形动态规划(树状DP)小结
树状动态规划定义 之所以这样命名树规,是因为树形DP的这一特殊性:没有环,dfs是不会重复,而且具有明显而又严格的层数关系.利用这一特性,我们可以很清晰地根据题目写出一个在树(型结构)上的记忆化搜索的 ...
- 【ACM/ICPC2013】树形动态规划专题
前言:按照计划,昨天应该是完成树形DP7题和二分图.最大流基础专题,但是由于我智商实在拙计,一直在理解树形DP的思想,所以第二个专题只能顺延到今天了.但是昨天把树形DP弄了个5成懂我是很高兴的!下面我 ...
- 【树形动态规划】【CTSC1997】选课 解题报告
CTSC1997-选课 描述 学校实行学分制.每门的必修课都有固定的学分,同时还必须获得相应的选修课程学分.学校开设了N(N<300)门的选修课程,每个学生可选课程的数量M是给定的.学生选修了这 ...
- 「洛谷2495」「BZOJ3052」「SDOI2001」消耗战【虚树+树形动态规划】
题目大意 给你\(k\)个点,让这一些点和一号节点断开,删去某一些边,求最小的删去边权之和. 做题的心路历程 做了\(HG\)昨天的模拟赛,深深感觉到了窝的菜,所以为了\(A\)掉T1这一道毒瘤,窝就 ...
- Codeforces 1000G Two-Paths 树形动态规划 LCA
原文链接https://www.cnblogs.com/zhouzhendong/p/9246484.html 题目传送门 - Codeforces 1000G Two-Paths 题意 给定一棵有 ...
- 树形动态规划(树形DP)入门问题—初探 & 训练
树形DP入门 poj 2342 Anniversary party 先来个题入门一下~ 题意: 某公司要举办一次晚会,但是为了使得晚会的气氛更加活跃,每个参加晚会的人都不希望在晚会中见到他的直接上 ...
- BZOJ1040 [ZJOI2008]骑士 基环树林(环套树) 树形动态规划
欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题意概括 有n个人,每一个人有一个最恨的人. 并且,每一个人有一个权值. 一个人不可以和他最恨的人同时被选中. 现在请你求出在 ...
- Vijos1906 联合权值 NOIP2014Day1T2 树形动态规划
欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - Vijos1906 题意概括 有一棵树,每一个节点都有一个权值w[i].下面说的x,y都是该树中的节点. 对于 ...
随机推荐
- The 2018 ACM-ICPC Asia Qingdao Regional Contest K XOR Clique
K XOR Clique BaoBao has a sequence a1,a2,...,an. He would like to find a subset S of {1,2,. ...
- Qt-Qml-播放视频-失败版-只有声音没有图像
失败版代码 import QtQuick 2.7 import QtQuick.Controls 2.0 import QtQuick.Layouts 1.0 import QtMultimedia ...
- katalon系列五:使用Katalon Studio手动编写WEB自动化脚本
上一篇主要讲了怎么录制脚本,这次我们看看怎么手动编写脚本,接下来就编写一个简单的用百度搜索的脚本. 1.我们先抓取页面上的元素,点击工具栏上的Spy Web按钮(地球上有个绿点),URL输入百度地址, ...
- Siki_Unity_1-4_C#编程(零基础)
1-4 C#编程(零基础) 任务1:第一章课程资料 任务2:简介 任务3:安装设置IDE工具 Unity内置IDE:MonoDevelop 推荐Visual Studio 下载/安装 VS Commu ...
- MySql优化浅析
优化点:合理的使用索引,可以大幅度提升sql查询效率,特别查询的表的数据量大的时候,效果明显.一.引言 公司的产品XX出行上线正式运营,随着数据量的变大,司机2000+,日订单1万+,注册乘客26W+ ...
- java对json文件的操作
第一步:通过FileReader读取json文件第二步:使用BufferReader,先通过I/O读取一定大小的数据缓存到数组中,然后再从数组取出数据.第三步:用一个字符串把每次传来的数据处理后写到新 ...
- Bcp 使用心得【转】
在做这方面研究的时候,的确遇到了不少麻烦. 首先在做bcp的时候,要开通大数据量访问权限 一.基于sql语句的导入导出 如果是基于SQL语句的导入导出,需要使用存储过程“master..xp_cmds ...
- 小程序的picker的range 是一个 Object Array (对象数组)
小程序的picker的range 是一个 Object Array (对象数组) 数据: array: [{'id':1,'name':'Android'},{'id':2,'name':'IOS'} ...
- NProgress.js加载进度插件的简单实用方法
NProgress.js 说明: NProgress是基于jquery的,且版本要 >1.8 下载地址: https://github.com/rstacruz/nprogress API: N ...
- c# 调取 c++ dll____c#调用dll
1.以海康摄像头dll为例.(文章转载https://www.cnblogs.com/smartsensor/p/4343744.html) 海康SDK编程指南 目前使用的海康SDK包括IPC_SDK ...