动态规划-DP 完整版
动态规划
学完了五大基础dp 做个简单总结
dp特征
动态规划问题 首要是找到做题的目的 是求最大/小值 还是其他;
其二 要确定问题的状态转移方程 这是关键;
第三 为dp数组找到边界、
最后 检查是否需要结合其他相关知识 如树 dfs等;
别忘了检查多测输入 数组变量置零等易错点。
背包dp
以背包为抽象模型 主要依据某一条件限制求出另一值的最优解
- 01背包
只有两个值 抽象化为体积和价值 要在体积一定的情况下找到价值的最大
状态转移方程:
\]
\(\qquad\,\,\)优化为一维:
\]
code:
点击查看代码
int w[N],v[N],dp[N];
for(int i=1;i<=n;i++)
for(int j=Vm;j>=w[i];j--)
dp[j]=max(dp[j],dp[j-w[i]]+v[i]);
- 完全背包
在01背包基础上 物品没有了数量的限制 可以有无数个
状态转移方程总体相同 更改了第二层体积循环的顺序
code:
点击查看代码
for(int i=1;i<=n;i++)
for(int j=w[i];j<=V;j++)
dp[j]=max(dp[j],dp[j-w[i]]+v[i];
- 多重背包
在01背包基础上 添加了部分可以取n次的物品
此类题 思路是在输入时就将数据处理成01背包 然后直接套用01背包板子即可
code:
点击查看代码
for(int i=1;i<=n;i++)
{
int w,v,s;//体积 价值 数量
int k=1;
cin>>w>>v>>s;
while(k<=s)
{
ww[++cnt]=k*w;
vv[cnt]=k*v;
s-=k;
k*=2;
}
if(s)
{
ww[++cnt]=s*w;
vv[cnt]=s*v;
}
}
for(int i=1;i<=cnt;i++)
for(int j=V;j>=ww[i];j--)
dp[j]=max(dp[j],dp[j-ww[i]]+vv[i]);
混合背包
即01 完全 多重背包的综合版
方法是将多重背包转化为01背包求解即可
code:
(偷个懒 直接截图了Qwq分组背包
定体积 若干组物品 每组物品只能选一个
在读入同时直接进行运算
code:
点击查看代码
scanf("%d%d",&n,&V);//组数 体积
for(int i=1;i<=n;i++)
{
scanf("%d",&t);//组中物品数
for(int j=1;j<=t;j++)
scanf("%d%d",&w[i],&v[i]);
for(int j=c;j>=0;j--)
//这里要先遍历体积再遍历物品 确保每组物品只取一个
for(int k=1;k<=t;k++)
{
if(j<w[k])continue;
dp[j]=max(dp[j],dp[j-w[k]]+v[k]);
}
}
特别的 每组最少取一个
- 二维费用背包
即在01背包体积 价值两个条件下 增加一个抽象为质量的限制条件 使结果既不超过背包体积 也不超过能承受的最大质量
嗯 直接枚举即可
code:
点击查看代码
for(int i=1;i<=n;i++)
for(int j=V;j>=w[i];j--)
for(int k=M;k>=m[i];k--)
dp[j][k]=max(dp[j][k],dp[j-w[i]][k-m[i]]+v[i]);
线性dp
(比较抽象的一种dp 非常依靠玄学
该dp主要指一个状态包含多个维度 每个维度上都具有线性变化的阶段(晕晕
我们按例题进行分析
- LIS(最长上升序列)
题目在这里
问题很好解决 转移方程如下:
\]
\(\qquad\quad\,\,(0<=j<i,a[j]<a[i])\)
\(\qquad\,\,\)还有一点 就是这道题要求输出路径 我们还需要添加一个数组来递归输出
code:
点击查看代码
#include<bits/stdc++.h>
#define fo(x,y,z) for(int (x)=(y);(x)<=(z);(x)++)
#define foo(x,y,z) for(int (x)=(y);(x)<(z);(x)++)
#define fu(x,y,z) for(int (x)=(y);(x)>=(z);(x)--)
#define opop cout<<"-------------------------"<<endl;
using namespace std;
inline int qr(){
char ch=getchar();int x=0,f=1;
for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;
for(;ch>='0'&&ch<='9';ch=getchar())x=(x<<3)+(x<<1)+(ch^48);
return x*f;
}
#define qr qr()
typedef long long ll;
const int Ratio=0;
const int N=10005;
const int maxx=0x3f3f3f;
int n,ans=0,mo=0;
int dh[N],zl[N],yy[N];
void read()
{
int x;
while(scanf("%d",&x)!=EOF)
dh[++n]=x;
}
void DrRatio()
{
fo(i,1,n)
{
zl[i]=1;
fo(j,1,i-1)
if(dh[i]>dh[j]&&zl[i]<zl[j]+1)
{
zl[i]=zl[j]+1;
yy[i]=j;
}
if(ans<zl[i])
{
ans=zl[i];
mo=i;
}
}
}
void opp(int x)
{
if(x==0)return;
opp(yy[x]);
printf("%d ",dh[x]);
}
void op()
{
printf("max=%d\n",ans);
opp(mo);
}
int main()
{
read();
DrRatio();
op();
return Ratio;
}
- 拦截导弹
题目在这里
第一问很简单 最长不上升子序
第二问需要用到Dilworth定理 不多阐述
code:
点击查看代码
int n,i,cnt=0,j,t;
while(cin>>a[cnt]){
cnt++;
}
int ans=0;
for(i=0;i<cnt;i++)
{
dp[i]=1;
for(j=0;j<cnt;j++)
{
if(a[i]<=a[j]&&i!=j)
dp[i]=max(dp[i],dp[j]+1);
}
ans=max(ans,dp[i]);
}
cout<<ans<<endl;
memset(dp,0,sizeof dp);
ans=0;
for(i=0;i<cnt;i++)
{
dp[i]=1;
for(j=0;j<cnt;j++)
{
if(a[i]>a[j]&&i!=j)
dp[i]=max(dp[i],dp[j]+1);
}
ans=max(ans,dp[i]);
}
cout<<ans<<endl;
- 麻烦的聚餐
题目在这里
这道题旨在于将给定的序列用最少的次数变成一个不上升或不下降序列
常规方法可能会超时 所以需要加一些优化
首先 读入同时倒序存储另一个数组
fo(i,1,n)
dh[i]=qr,yy[n+1-i]=dh[i];
\(\qquad\,\,\)然后 将除dp[0]以外所用dp数组内所有值赋为极大值
\(\qquad\,\,\)按正序和倒序遍历两次 取结果中最小的哪一个
code:
点击查看代码
void DrRatio()
{
fo(i,1,n)
fo(j,1,3)
{
zl[i][j]=maxx;
fu(k,j,1)
zl[i][j]=min(zl[i][j],zl[i-1][k]);
if(j!=dh[i])
zl[i][j]++;
}
fo(i,1,3)
ans=min(zl[n][i],ans);
fo(i,1,n)
fo(j,1,3)
{
zl[i][j]=maxx;
fu(k,j,1)
zl[i][j]=min(zl[i][j],zl[i-1][k]);
if(j!=yy[i])
zl[i][j]++;
}
fo(i,1,3)
ans=min(zl[n][i],ans);
}
- 打鼹鼠
题目在这里
这道题是个典型dp 判断方式也很简单
方法是定义一个以时间早晚排序的结构体 只要两者的距离差不大于时间差即可
code:
点击查看代码
struct mole
{
int time,x,y;
}dh[N];
bool cmp(mole A,mole B)
{
return A.time<B.time;
}
bool pd(mole A,mole B)
{
int tc=A.time-B.time,my=abs(B.y-A.y),mx=abs(B.x-A.x);
return (mx+my)<=tc?true:false;
}
void read()
{
n=qr,m=qr;
fo(i,1,m)
dh[i].time=qr,dh[i].x=qr,dh[i].y=qr;
sort(dh+1,dh+m+1,cmp);
}
void DrRatio()
{
fo(i,1,m)
{
zl[i]=1;
fu(j,i-1,1)
if(pd(dh[i],dh[j]))
zl[i]=max(zl[i],zl[j]+1);
ans=max(ans,zl[i]);
}
}
区间dp
这类题一般是将原序列化分为若干个区间 然后合并得出最优解 故也称合并动规
提到区间dp 就不得不联系到贪心 区间dp的题 一眼看上去都可以用贪心来做 但很容易举出反例 因此在觉得一道题是贪心的时候 先试着举出反例 若存在反例 则要按区间dp的思想来做
同上 这一类也用例题的形式回顾
- 石子合并问题
题目在这里
乍一眼看上去是贪心 但试着算一下 很容易发现不对劲
首先 题目中石子摆成了一个环 因此我们采用扩大数组为原来二倍的方法存数据
然后 用前缀和的形式存储到每一位石子的值
状态转移方程为:
\]
\(\qquad\,\,\)其中\(j=len+i-1\)
\(\qquad\,\,\)边界为:dp[i][i]=0
\(\qquad\,\,\)最终取值为以每一位为首的环的最大值 表达式为:
\]
code:
点击查看代码
void read()
{
n=qr;
memset(rm,0,sizeof rm);
memset(dh,-1,sizeof dh);
fo(i,1,n)
{
yy[i]=qr;
rm[i]=rm[i-1]+yy[i];
dh[i][i]=0;
}
}
void DrRatio()
{
fo(i,1,n)
{
rm[i+n]=rm[i+n-1]+yy[i];
dh[i+n][i+n]=0;
}
fo(len,2,n)
fo(i,1,2*n-len)
{
int j=len+i-1;
dh[i][j]=max(dh[i+1][j],dh[i][j-1])+rm[j]-rm[i-1];
}
fo(i,1,n)
maax=max(maax,dh[i][i+n-1]);
}
- 整数划分
题目在这里
现在看来 这是一道明显的区间dp
首先一个a数组 用来存储第i到j位的数
然后dp数组 前i位分成j部分的最优解
状态转移方程为:
\]
\(\qquad\,\,\)其中\(0<=k<i\)
\(\qquad\,\,\)边界为:
\]
\(\qquad\,\,\)对了 这一题还需要输出划分结果 因此在状态转移时要使用if判断 更改后随机更新y数组的值 最后递归输出
code:
点击查看代码
#include<bits/stdc++.h>
#define fo(x,y,z) for(int (x)=(y);(x)<=(z);(x)++)
#define foo(x,y,z) for(int (x)=(y);(x)<(z);(x)++)
#define fu(x,y,z) for(int (x)=(y);(x)>=(z);(x)--)
#define opop cout<<"-------------------------"<<endl;
using namespace std;
inline int qr(){
char ch=getchar();int x=0,f=1;
for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;
for(;ch>='0'&&ch<='9';ch=getchar())x=(x<<3)+(x<<1)+(ch^48);
return x*f;}
#define qr qr()
typedef long long ll;
const int Ratio=0;
const int N=105;
const int maxx=0x3f3f3f;
int T;
ll dh[N][N],yy[N][N],zl[N][N];
ll m,ne[N],len;
char s[N];
void read()
{
memset(yy,-1,sizeof yy);
memset(zl,-1,sizeof zl);
ne[0]=0;
scanf("%s%lld",s,&m);
m--;
len=strlen(s);
fo(i,0,len-1)
{
dh[i][i]=s[i]-'0';
fo(j,i+1,len-1)
dh[i][j]=dh[i][j-1]*10+s[j]-'0';
}
fo(i,0,len-1)
{
zl[i][0]=dh[0][i];
yy[i][0]=-1;
}
}
void dg(ll x,ll y)
{
if(yy[x][y]==-1)return;
ne[++ne[0]]=yy[x][y];
dg(yy[x][y],y-1);
}
void DrRatio()
{
fo(i,0,len-1)
fo(j,1,m)
fo(k,0,i-1)
if(zl[k][j-1]!=-1&&zl[k][j-1]*dh[k+1][i]>zl[i][j])
{
zl[i][j]=zl[k][j-1]*dh[k+1][i];
yy[i][j]=k;
}
}
void op()
{
printf("%lld\n",zl[len-1][m]);
dg(len-1,m);
fo(i,0,len-1)
{
printf("%c",s[i]);
if(ne[0]!=0&&i==ne[ne[0]])
{
printf(" ");
ne[0]--;
}
}
printf("\n");
}
int main()
{
T=qr;
while(T--)
{
read();
DrRatio();
op();
}
return Ratio;
}
- 最大乘积(印象最深的一集 写了一上午
题目在这里
看上去与上一题类似 但坑点就在于 需要用高精度
整体思路大致相同 求出i到j位的数 然后相乘
因为用到高精度 需要记录长度 因此我选择定义一个结构体 让所有运算在结构体内进行
这次的详解放到代码注释里了~
code:
点击查看代码
#include<bits/stdc++.h>
#define fo(x,y,z) for(int (x)=(y);(x)<=(z);(x)++)
#define foo(x,y,z) for(int (x)=(y);(x)<(z);(x)++)
#define fu(x,y,z) for(int (x)=(y);(x)>=(z);(x)--)
#define opop cout<<"-------------------------"<<endl;
using namespace std;
inline int qr(){
char ch=getchar();int x=0,f=1;
for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;
for(;ch>='0'&&ch<='9';ch=getchar())x=(x<<3)+(x<<1)+(ch^48);
return x*f;}
#define qr qr()
typedef long long ll;
const int Ratio=0;
const int N=55;
const int maxx=0x3f3f3f;
int n,m;
char s[N];
struct rm
{
int len;
int a[105]={};
}dh[N][N],zl[N][N];
rm sw(rm A)//众所周知 高精度运算需要倒着进行 将A首尾倒置
{
int b[105];
fo(i,0,A.len-1)
{
b[i]=A.a[A.len-i-1];
}
fo(i,0,A.len-1)
{
A.a[i]=b[i];
}
return A;
}
rm cheng(rm A,rm B)//高精乘 不必多说
{
rm C;
A=sw(A);
B=sw(B);
C.len=A.len+B.len;
fo(i,0,A.len-1)
fo(j,0,B.len-1)
{
C.a[i+j]+=A.a[i]*B.a[j];
C.a[i+j+1]+=C.a[i+j]/10;
C.a[i+j]%=10;
}
while(C.a[C.len-1]==0&&C.len>1)C.len--;
A=sw(A),B=sw(B),C=sw(C);
return C;
}
rm Bma(rm A,rm B)//比较A与B的大小 为状态转移方程用
{
if(A.len>B.len)
return A;
else if(A.len<B.len)
return B;
else
{
fo(i,0,A.len-1)
if(A.a[i]>B.a[i])
return A;
else if(A.a[i]<B.a[i])
return B;
return A;
}
}
void read()
{
n=qr,m=qr;
fo(i,1,n)
cin>>s[i];
fo(i,1,n)
{
dh[i][i].len=1;//初始化dh存i到i位的数
dh[i][i].a[0]=s[i]-'0';
fo(j,i+1,n)//结论推导:存i到j位的数
{
dh[i][j].len=dh[i][j-1].len+1;
fo(k,0,dh[i][j-1].len-1)
dh[i][j].a[k]=dh[i][j-1].a[k];
dh[i][j].a[dh[i][j-1].len]=s[j]-'0';
}
}
}
void DrRatio()
{
fo(i,1,n)
{
zl[i][0]=dh[1][i];//初始化/边界
fo(j,1,m)
fo(k,j,i-1)
{
rm Rm=cheng(zl[k][j-1],dh[k+1][i]);
zl[i][j]=Bma(zl[i][j],Rm);
}
}
}
void op()
{
fo(i,0,zl[n][m].len-1)
cout<<zl[n][m].a[i];
}
int main()
{
read();
DrRatio();
op();
return Ratio;
}
- 凸多边形的三角剖分
题目在这里
这题难想的点在于状态转移方程
首先 设一个多边形上的点为A
dp含义为i到j组成三角形的最小值
故点A后一点A+1必不能与A构成三角形
所以\(dp[A][A+1]=0\)
当然 自己和自己也不可能构成三角形
然后 在这个多边形上任选一点B
在AB间任选一点C
可以得到:AC间剖成三角形的最小值与CB间剖成三角形的最小值的和 再加上三角形ABC的值 就是AB间剖分最小值
状态转移方程为:
\]
\(\qquad\,\,\)其中\(j=len+i-1,j<=n;i<k<j\)
code:
点击查看代码
void read()
{
memset(zl,0x3f,sizeof zl);
n=qr;
fo(i,1,n)
scanf("%lld",&dh[i]);
fo(i,1,n)
zl[i][i]=zl[i][i+1]=0;
}
void DrRatio()
{
fo(len,1,n)
fo(i,1,n)
{
int j=min(len+i-1,n);
fo(k,i+1,j-1)
zl[i][j]=min(zl[i][j],zl[i][k]+zl[k][j]+dh[i]*dh[j]*dh[k]);
}
}
坐标dp
提到坐标 第一反应就是图
没错 坐标dp是需要存图的 但很简单 只用邻接矩阵即可
将数据存到图中 用遍历的方式找最优解 是坐标dp的精髓
- 传纸条
题目在这里
最经典的一道坐标dp题 题面也很清晰
直接来看状态转移方程
三维优化后为:
\]
\(\qquad\,\,\)k为走的步数
\(\qquad\,\,\)其中\(k<m+n;1<=i<n;i<j<=n\)
code:
点击查看代码
void read()
{
scanf("%d%d",&m,&n);
fo(i,1,m)
fo(j,1,n)
scanf("%d",&dh[i][j]);
// memset(zl,0,sizeof zl);
}
int Max(int a,int b,int c,int d)
{
int e=a;
if(b>e)e=b;
if(c>e)e=c;
if(d>e)e=d;
return e;
}
void DrRatio()
{
fo(k,3,m+n-1)
fo(i,1,n-1)
fo(j,i+1,n)
{
if(k<i+1||k<j+1)continue;
zl[k][i][j]=Max(zl[k-1][i][j],zl[k-1][i-1][j],zl[k-1][i][j-1],zl[k-1][i-1][j-1])+dh[k-i][i]+dh[k-j][j];
}
}
void op()
{
printf("%d\n",zl[m+n-1][n-1][n]);
}
- 矩阵取数游戏
题目在这里
恶心的点在于 状态转移方程很难想
好在 它可以将每一行分隔开单独看 并且用int128即可解决
状态转移方程如下:
\]
\(\qquad\,\,\)其中\(1<len<=m;1<=j<=m;k=j+len-1\)
code:
点击查看代码
int n,m,dh[N][N];
__int128 zl[N][N],ans=0;
void print(__int128 a)
{
if(a>9)
print(a/10);
putchar(a%10+'0');
}
void read()
{
n=qr,m=qr;
fo(i,1,n)
fo(j,1,m)
dh[i][j]=qr;
}
void DrRatio()
{
fo(i,1,n)
{
fo(j,1,m)
zl[j][j]=dh[i][j];
fo(l,2,m)
for(int j=1,k=j+l-1;k<=m;j++,k++)
zl[j][k]=max(zl[j+1][k]*2+dh[i][j],zl[j][k-1]*2+dh[i][k]);
ans+=zl[1][m]*2;
}
}
void op()
{
print(ans);
}
- 免费馅饼
题目在这里
这道题要用结构体存图
此外 还有两个关键点:
1>人站在最下面一格 所以下落高度要-1
2>不是整数时刻落下的接不到
直接上代码吧
code:
点击查看代码
#include <bits/stdc++.h>
#define fo(x,y,z) for(int (x)=(y);(x)<=(z);(x)++)
#define fu(x,y,z) for(int (x)=(y);(x)>=(z);(x)--)
#define foo(x,y,z) for(int (x)=(y);(x)<(z);(x)++)
using namespace std;
inline int qr()
{
char ch=getchar();int x=0,f=1;
for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;
for(;ch>='0'&&ch<='9';ch=getchar())x=(x<<3)+(x<<1)+(ch^48);
return x*f;
}
#define qr qr()
typedef long long ll;
const int Ratio=0;
const int N=1005;
const int maxx=0x7f7f7f7f;
int w,h,cnt,maax=-maxx,ans=0;
int a,b,c,d;
int yy[6]={0,-2,-1,0,1,2};
int zl[N][N];
struct rm
{
int tt,x,v;
}dh[10*N];
void read()
{
w=qr,h=qr;h--;
while(scanf("%d%d%d%d",&a,&b,&c,&d)!=EOF)
{
if(h%c!=0)continue;
dh[++cnt].x=b;
dh[cnt].v=d;
dh[cnt].tt=a+ceil(h/c);
}
}
void DrRatio()
{
fo(i,1,cnt)
{
zl[dh[i].x][dh[i].tt]+=dh[i].v;
maax=max(maax,dh[i].tt);
}
fu(j,maax-1,0)
fo(i,1,w)
{
ans=0;
fo(k,1,5)
if(i+yy[k]>0&&i+yy[k]<=w&&zl[i+yy[k]][j+1])
ans=max(ans,zl[i+yy[k]][j+1]);
zl[i][j]+=ans;
}
}
void op()
{
printf("%d\n",zl[w/2+1][0]);
}
int main()
{
read();
DrRatio();
op();
return Ratio;
}
- 三角蛋糕
题目在这里
这道题有个坑 如果只按题目给定的0和1来存 就会出现虽然数字构成了三角形 但是方向是反的 从而得到了错误答案
因此 要反着推一遍
状态转移方程为:
\]
\(\qquad\,\,\)注意 i与j的运算符号相反
code:
点击查看代码
#include <bits/stdc++.h>
#define fo(x,y,z) for(int (x)=(y);(x)<=(z);(x)++)
#define fu(x,y,z) for(int (x)=(y);(x)>=(z);(x)--)
#define foo(x,y,z) for(int (x)=(y);(x)<(z);(x)++)
using namespace std;
inline int qr()
{
char ch=getchar();int x=0,f=1;
for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;
for(;ch>='0'&&ch<='9';ch=getchar())x=(x<<3)+(x<<1)+(ch^48);
return x*f;
}
#define qr qr()
typedef long long ll;
const int Ratio=0;
const int N=505;
const int maxx=0x7f7f7f7f;
char s[N][N];
int n,ans=0;
int dh[N][N],zl[N][N];
void read()
{
n=qr;
fo(i,1,n)
scanf("%s",s[i]+1);//以1为起点
}
void DrRatio()
{
fo(i,1,2*n-1)//第一行特殊处理
if(s[1][i]!='1')
zl[1][i]=1,ans=1;
fo(i,2,n)
fu(j,2*(n-i)+1,1)//倒
{
if(s[i][j]!='1')
zl[i][j]=min(zl[i-1][j],min(zl[i-1][j+1],zl[i-1][j+2]))+1;//上一行左中右都不被损坏
if(j&1)
ans=max(ans,zl[i][j]);
}
if(s[n][1]=='1')dh[n][1]=1;
fu(i,n-1,1)//反着推一遍
fu(j,2*(n-i)+1,1)
{
if(s[i][j]!='1')
dh[i][j]=min(dh[i+1][j],min(dh[i+1][j-1],dh[i+1][j-2]))+1;
if(!(j&1))
ans=max(ans,dh[i][j]);
}
}
void op()
{
printf("%d\n",ans*ans);
}
int main()
{
read();
DrRatio();
op();
return Ratio;
}
树形dp
算法如其名 树形dp是建立在树上的dp
而树不存在回路 因此dfs是解决树形dp的主要方法
- 没有上司的舞会
最简单 最经典的树规题
\(dp[i][0]\)表示i没有参会
\(dp[i][1]\)表示i参会
状态转移方程为:
\(dp[x][0]+=max(dp[son[x][i]][0],dp[son[x][i]][1])\)
\(dp[x][1]+=dp[son[x][i]][0]\)
code:
点击查看代码
#include<bits/stdc++.h>
#define fo(x,y,z) for(int (x)=(y);(x)<=(z);(x)++)
#define foo(x,y,z) for(int (x)=(y);(x)<(z);(x)++)
#define fu(x,y,z) for(int (x)=(y);(x)>=(z);(x)--)
#define opop cout<<"-------------------------"<<endl;
using namespace std;
inline int qr(){
char ch=getchar();int x=0,f=1;
for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;
for(;ch>='0'&&ch<='9';ch=getchar())x=(x<<3)+(x<<1)+(ch^48);
return x*f;}
#define qr qr()
typedef long long ll;
const int Ratio=0;
const int N=10005;
const int maxx=0x3f3f3f;
vector<int>so[N];
int n,ro;
int zl[N][2],fx[N],joy[N];
void read()
{
n=qr;
fo(i,1,n)
joy[i]=qr;
fo(i,1,n)
{
int x=qr,y=qr;
if(i==n)break;
fx[x]=1;
so[y].push_back(x);
}
}
void rRatio(int x)
{
zl[x][0]=0;
zl[x][1]=joy[x];
for(int i=0;i<so[x].size();i++)
{
int a=so[x][i];
rRatio(a);
zl[x][0]+=max(zl[a][0],zl[a][1]);
zl[x][1]+=zl[a][0];
}
}
void DrRatio()
{
fo(i,1,n)
if(!fx[i])
{
ro=i;
break;
}
rRatio(ro);
}
void op()
{
printf("%d\n",max(zl[ro][0],zl[ro][1]));
}
int main()
{
read();
DrRatio();
op();
return Ratio;
}
- 三色二叉树
写了这一题的题解
在这里看
大体就这么多了 再想到会补充的
制作不易 求个推荐(✪ω✪)
动态规划-DP 完整版的更多相关文章
- 谷歌大脑科学家 Caffe缔造者 贾扬清 微信讲座完整版
谷歌大脑科学家 Caffe缔造者 贾扬清 微信讲座完整版 一.讲座正文: 大家好!我是贾扬清237,目前在Google Brain83,今天有幸受雷鸣师兄邀请来和大家聊聊Caffe60.没有太多准备, ...
- 如何安全的将VMware vCenter Server使用的SQL Server Express数据库平滑升级到完整版
背景: 由于建设初期使用的vSphere vCenter for Windows版,其中安装自动化过程中会使用SQL Server Express的免费版数据库进行基础环境构建.而此时随着业务量的增加 ...
- Android版的菜谱客户端应用源码完整版
Android版的菜谱客户端应用源码完整版,这个文章是从安卓教程网转载过来的,不是本人的原创,希望能够帮到大家的学习吧. <ignore_js_op> 152936qc7jdnv6vo0c ...
- sed实例精解--例说sed完整版
原文地址:sed实例精解--例说sed完整版 作者:xiaozhenggang 最近在学习shell,怕学了后面忘了前面的就把学习和实验的过程记录下来了.这里是关于sed的,前面有三四篇分开的,现在都 ...
- flexbox-CSS3弹性盒模型flexbox完整版教程
原文链接:http://caibaojian.com/flexbox-guide.html flexbox-CSS3弹性盒模型flexbox完整版教程 A-A+ 前端博客•2014-05-08•前端开 ...
- 转贴 IT外企那点儿事完整版
转贴 IT外企那点儿事完整版 第一章:外企也就那么回儿事(http://www.cnblogs.com/forfuture1978/archive/2010/04/30/1725341.html) 1 ...
- C#.Net 上传图片,限制图片大小,检查类型完整版
C#.Net 上传图片,限制图片大小,检查类型完整版 源代码: 处理图片类,如检查图片大小,按宽度比例缩小图片 public class CImageLibrary{ public enum Va ...
- office2016 软件全集 官方下载免费完整版(含破解文件)不含垃圾软件 win10完美激活
office2016官方下载免费完整版是新一代办公软件,office2016官方下载免费完整版已经分享到下面,office2016官方下载免费完整版包括了Word.Excel.PowerPoint.O ...
- 老王Python培训视频教程(价值500元)【基础进阶项目篇 – 完整版】
老王Python培训视频教程(价值500元)[基础进阶项目篇 – 完整版] 教学大纲python基础篇1-25课时1.虚拟机安装ubuntu开发环境,第一个程序:hello python! (配置开发 ...
- thinkPHP3.2.3完整版 在sae上面的部署
第一步: thinkPHP3.2.3完整版,目录结构如下 第二步:在新浪sae上面创建一个新应用 第三步:用svn down,下来会有两个文件:index.php.config.ya ...
随机推荐
- dev DEV控件:gridControl常用属性设置
引用:https://www.cnblogs.com/kingsliu/articles/6145679.html 1.隐藏最上面的GroupPanelgridView1.OptionsView.Sh ...
- CentOS 6.5 ZIP、RAR文件压缩解压操作详解
============zip文件的操作================= zip -r data.zip data 解释:将data文件夹压缩成了data.zip格式. unzip data.z ...
- sql 语句系列(列举非索引外键)[八百章之第九章]
列举非索引外键 列举出那些外键没有添加索引. 目的: 1.减少锁. 2.外键添加索引,提示了查询性能,因为要与父表做连接查询做笛卡尔积. 下面只要会复制即可,没有会去从新写一遍的. select fk ...
- 重新整理 .net core 实践篇—————Entity的定义[二十五]
前言 简单介绍一下实体模型的设计. 正文 前文提及了我们的应用分为: 共享层 基础设施层 领域层 应用层 今天来介绍领域模型层. 前文提及到领域模型在共享层有一个领域模型抽象类库. 里面有这些类: 先 ...
- few-shot-learning for object detection
github https://github.com/LiuXinyu12378/few-shot-learning-for-object-detection train.py from __futu ...
- 见鬼了!我家的 WiFi 只有下雨天才能正常使用...
这是作者大学时期在家里遇到的一个非常奇怪的网络问题,作者的父亲是一名经验丰富的网络工程师,他们家里使用了一个复杂的网络设置,通过 Wi-Fi 桥接的方式,将父亲公司的高速商业网络连接到家中.但是有一天 ...
- 微信、企微小程序使用taro对位置权限进行处理
1.功能 当用户未授权地理位置权限时,引导用户开启地理位置权限,区别于之前的uni处理,uni的处理 的处理没有手机系统关闭位置权限的处理,但是uni文章中对于打开位置权限后重新返回小程序有做权限重获 ...
- MaxCompute非事务表如何更新数据
简介: 本文主要讲解如何通过insert overwrite更新数据 背景 对于大数据中的大多数存储格式,支持随机更新非常复杂.它需要扫描大型文件,MaxCompute推出了最新的功能Transact ...
- 延迟绑定与retdlresolve
延迟绑定与retdlresolve 我们以前在ret2libc的时候,我们泄露的libc地址是通过延迟绑定实现的,我们知道,在调用libc里面的函数时候,它会先通过plt表和gor表绑定到,函数真实地 ...
- [FAQ] wechaty 与 wechaty-puppet-padplus 生态安全吗
答案是肯定有风险. 非技术角度讲,使用这种方式登录微信存在被微信官方风控的可能性,需要特别注意. 另外,以下是 wechaty 项目说明文件中截取的内容: 我们可以看到,除了微信官方方面的风险,我们的 ...