洛谷:P2015 二叉苹果树(dp树,普及/提高-)

题目:

在这里插入图片描述

分析:看错题目,要删几个!。。。减一下就欧克啦。但是,减去一个不单单是减去了一个啊。是减去了一串啊!

代码:

#include<bits/stdc++.h>
using namespace std;
int m,n;
int A[101][2];//存放子树。
vector<vector<int> >vv; 
int B[101][101];//存放树上的苹果
long long D[101][101];
int t[101];//存放个数。
map<int,int> mm;
long long f(int x,int y)
{
 if(D[x][y]!=-1) return D[x][y];
 //特殊。
 if(y==0)
 {//统计 
  if(A[x][0]==-1) return 0;
  D[x][y]=B[x][A[x][0]]+f(A[x][0],y)+B[x][A[x][1]]+f(A[x][1],y);
  return D[x][y];
 }
 if(A[x][0]==-1||t[x]<y) return -(1<<30);
 if(t[x]==y) return 0;
 D[x][y]=0;
 //都不
 long long a=-1;
 for(int i=0;i<=y;i++) a=max(a,B[x][A[x][1]]+B[x][A[x][0]]+f(A[x][0],i)+f(A[x][1],y-i));
 //左右
 long long b=-1; 
 if(y>=1+t[A[x][0]])
 b=B[x][A[x][1]]+f(A[x][1],y-1-t[A[x][0]]);
 if(y>=1+t[A[x][1]])
 b=max(b,B[x][A[x][0]]+f(A[x][0],y-1-t[A[x][1]]));
 D[x][y]=max(a,b);
 if(D[x][y]<0) D[x][y]=-(1<<30);
 return D[x][y];
}
void f2(int x)
{
 mm[x]=1;
 for(int i=0;i<vv[x].size();i++)
 {
  if(mm[vv[x][i]]==0) 
  {
   if(A[x][0]==-1){
    A[x][0]=vv[x][i];
   }
   else{
    A[x][1]=vv[x][i];
   }
   f2(vv[x][i]);
   } 
 }
}
int f3(int x)
{
 if(t[x]!=0) return t[x];
 if(A[x][0]==-1) {
  t[x]=0;
  return 0;
 }
 t[x]=2+f3(A[x][1])+f3(A[x][0]);
 return t[x];
} 
int main()
{
 cin>>m>>n;
 memset(D,-1,sizeof(D));
 memset(A,-1,sizeof(A));
 memset(t,0,sizeof(t));
 vector<int> v;
 for(int i=0;i<=m;i++) vv.push_back(v);
 for(int i=1;i<m;i++)
 {
  int a,b,c;
  cin>>a>>b>>c;
  B[a][b]=B[b][a]=c;
  vv[a].push_back(b);
  vv[b].push_back(a);
 }
 f2(1);
 f3(1);
 //long long c=0;
 cout<<f(1,m-1-n);
}

再次看这个题的时候,第一个回想起就是当时遇到的坑:

在这里插入图片描述

1枝条删除了相当于把其作为根的枝条全部删除了,是要算数目的。

方程:A【i】【j】表示编号为i的保留j个枝条时的最大值。

然后左右分配就行啦。(因为是二叉树,比较简单)

优化:可以统计每个节点最多保存的个数。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值