二叉苹果树
题目描述
有一棵二叉苹果树,如果数字有分叉,一定是分两叉,即没有只有一个儿子的节点。这棵树共N个节点,标号1至N,树根编号一定为1。
我们用一根树枝两端连接的节点编号描述一根树枝的位置。一棵有四根树枝的苹果树,因为树枝太多了,需要剪枝。但是一些树枝上长有苹果,给定需要保留的树枝数量,求最多能留住多少苹果。
我们用一根树枝两端连接的节点编号描述一根树枝的位置。一棵有四根树枝的苹果树,因为树枝太多了,需要剪枝。但是一些树枝上长有苹果,给定需要保留的树枝数量,求最多能留住多少苹果。
输入描述:
第一行两个数N和Q,N表示树的节点数,Q表示要保留的树枝数量。
接下来N-1行描述树枝信息,每行三个整数,前两个是它连接的节点的编号,第三个数是这根树枝上苹果数量。
输出描述:
输出仅一行,表示最多能留住的苹果的数量。
示例1
输入
5 2 1 3 1 1 4 10 2 3 20 3 5 20
输出
21
备注:
对于100%的数据,1≤Q≤N≤100,N≠11,每根树枝上苹果不超过30000个。
题目思路:
f[i][j]表示以i为根节点的子树保留j根树枝的最多苹果数,d[i][j]表示i节点到j节点树枝上的苹果数。
vector作为邻接表记录与每个节点相邻的节点(注意dfs时不能走父节点)。
代码如下(记忆化搜索实现):
#include<bits/stdc++.h>
#define ll long long
using namespace std;
int n,m,f[101][101],d[101][101];
vector<int> v[101];
int dfs(int x,int y,int fa)
{
vector<int> child;
int ans = 0;
if(f[x][y]!=-1)
return f[x][y];
if(x!=1&&v[x].size()==1||y==0)
{
f[x][y] = ans;
return ans;
}
else if(v[x].size()==2&&x!=1||x==1&&v[x].size()==1)
{
for(int i = 0;i<v[x].size();i++)
if(v[x][i]!=fa)
child.push_back(v[x][i]);
ans = d[x][child[0]]+dfs(child[0],y-1,x);
f[x][y] = ans;
return ans;
}
else
{
for(int i = 0;i<v[x].size();i++)
if(v[x][i]!=fa)
child.push_back(v[x][i]);
if(y>=2)
for(int i = 0;i<y-1;i++)
ans = max(ans,d[x][child[0]]+d[x][child[1]]+dfs(child[0],i,x)+dfs(child[1],y-i-2,x));
if(y>=1)
{
ans = max(ans,d[x][child[0]]+dfs(child[0],y-1,x));
ans = max(ans,d[x][child[1]]+dfs(child[1],y-1,x));
}
f[x][y] = ans;
return ans;
}
}
int main()
{
memset(d,-1,sizeof(d));
memset(f,-1,sizeof(f));
int a,b,c;
cin>>n>>m;
for(int i = 0;i<n-1;i++)
{
cin>>a>>b>>c;
v[a].push_back(b);
v[b].push_back(a);
d[a][b] = c;
d[b][a] = c;
}
cout<<dfs(1,m,0);
return 0;
}
如果有错误的地方,还请各位大佬指正。