二叉苹果树(树形dp)

二叉苹果树

题目描述

有一棵二叉苹果树,如果数字有分叉,一定是分两叉,即没有只有一个儿子的节点。这棵树共N个节点,标号1至N,树根编号一定为1。
我们用一根树枝两端连接的节点编号描述一根树枝的位置。一棵有四根树枝的苹果树,因为树枝太多了,需要剪枝。但是一些树枝上长有苹果,给定需要保留的树枝数量,求最多能留住多少苹果。
tree.png

输入描述:

第一行两个数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;
}

  

如果有错误的地方,还请各位大佬指正。

猜你喜欢

转载自www.cnblogs.com/loganacmer/p/11296870.html