• 二叉苹果树


    传送门
    中文题面:

    题目描述

    有一棵苹果树,如果树枝有分叉,一定是分 2 叉(就是说没有只有 1 个儿子的结点,这棵树共有N 个结点(叶子点或者树枝分叉点),编号为1-N,树根编号一定是1。
    我们用一根树枝两端连接的结点的编号来描述一根树枝的位置。下面是一颗有 4 个树枝的树:
    2 5
    /
    3 4
    /
    1
    现在这颗树枝条太多了,需要剪枝。但是一些树枝上长有苹果。
    给定需要保留的树枝数量,求出最多能留住多少苹果。

    输入格式

    第1行2个数,N 和Q(1<=Q<= N,1<N<=100)。N 表示树的结点数,Q 表示要保留的树枝数量。
    接下来 N-1 行描述树枝的信息。
    每行3个整数,前两个是它连接的结点的编号,第3个数是这根树枝上苹果的数量。
    每根树枝上的苹果不超过30000个。

    输出格式

    一个数,最多能留住的苹果的数量。

    样例数据 1

    输入

    5 2
    1 3 1
    1 4 10
    2 3 20
    3 5 20

    输出

    21
    

    题目分析

    此题是选课的简化版,因为规定了树是一颗二叉树,dp[i][j]表示以i为根节点的子树选择j条边的最大值,因为是棵树,所以可以将边权转移到点权上,剩下的就与选课一题异曲同工。
    若选择当前节点:

    1. 此节点是根节点的话,左右儿子一共分担j个。枚举即可。
    2. 此节点不是根节点,左右儿子一共分担j-1个。
      若不选择当前节点:dp = 0。
      取较优值。

    code

    #include<bits/stdc++.h>
    using namespace std;
    
    const int N = 100;
    int ecnt, adj[N + 5], go[N * 2 + 5], nxt[N * 2 + 5], val[N + 5], len[N * 2 + 5];
    int fa[N + 5], ch[N + 5][2];
    typedef long long ll;
    ll dp[N + 5][N + 5];
    int n, m;
    
    inline void addEdge(int u, int v, int c){
    	nxt[++ecnt] = adj[u], adj[u] = ecnt, go[ecnt] = v, len[ecnt] = c;
    	nxt[++ecnt] = adj[v], adj[v] = ecnt, go[ecnt] = u, len[ecnt] = c;
    }
    
    inline void dfs(int u, int f){
    	fa[u] = f;
    	int cnt = -1;
    	for(int e = adj[u]; e; e = nxt[e]){
    		int v = go[e];
    		if(v == f) continue;
    		ch[u][++cnt] = v;
    		val[v] = len[e];
    		dfs(v, u);
    	}
    }
    
    inline ll DP(int u, int k){
    	if(u == 0) return dp[u][k] = 0;
    	if(dp[u][k] != -1) return dp[u][k];
    	
    	dp[u][k] = 0;
    	//选择这个
    	for(int i = 0; i <= k - 1 + (u == 1 ? 1 : 0); i++){
    		DP(ch[u][0], i);
    		DP(ch[u][1], k - 1 + (u == 1 ? 1 : 0) - i);
    		dp[u][k] = max(dp[u][k], 1LL * val[u] + dp[ch[u][0]][i] + dp[ch[u][1]][k - 1 + (u == 1 ? 1 : 0) - i]);
    	}
    	
    	return dp[u][k]; 
    }
    
    int main(){
    	ios::sync_with_stdio(false);
    	cin.tie(NULL), cout.tie(NULL);
    	cin >> n >> m;
    	for(int i = 1; i < n; i++){
    		int x, y, c;
    		cin >> x >> y >> c;
    		addEdge(x, y, c);
    	}
    	dfs(1, 0);
    //	for(int i = 1; i <= n; i++) cout<<i<<": "<<fa[i]<<" "<<ch[i][0]<<" "<<ch[i][1]<<" "<<val[i]<<endl;
    	memset(dp, -1, sizeof dp);
    	DP(1, m);
    	cout << dp[1][m] << endl;
    	return 0;
    }
    
  • 相关阅读:
    iOS集成ijkplayer视频直播框架,遇到的bug和坑...
    push notification获取device token
    ios xcode Code signing failed 解决方案
    ios 返回指定导航控制器
    ios git 终端提交
    mysql问题集合
    mysql 备份和恢复
    cacti 异常问题
    硬盘各项检测
    LVS DR模式(直接路由模式)
  • 原文地址:https://www.cnblogs.com/CzYoL/p/7532839.html
Copyright © 2020-2023  润新知