zoukankan      html  css  js  c++  java
  • 「Luogu2014」 选课

    Problem

    树上背包问题的典例,记下来


    solution

    (dp[x][t])表示以(x)为子树,选(t)门课获得的最大学分

    (p)(x)的子节点数量,(c_i)(x)的子节点(y_i)选修的课数

    转移方程如下

    [dp[x][t]=max_{sum_{i=1}^pc_i=t-1}{sum_{i=1}^pdp[y_i][c_i]}+pnt[x] ]

    事实上,这是一个分组背包模型,对于每个节点(x),每个子节点(y_i)是一个组,在其中选取不超过(1)个元素(c_i)加入背包。将当前枚举到的组作为阶段

    对于没有先修课的课程,我们可以将一个超级根节点(0)作为它们的父节点,方便计算

    Code

    #include <cstdio>
    #include <algorithm>
    #include <iostream>
    #include <cstring>
    #include <cmath>
    #include <cstdlib>
    #include <vector>
    #define maxn 305
    #define maxm 305
    using namespace std;
    typedef long long ll;
    
    int n,m;
    vector<int> son[maxn];
    int prt[maxn];
    int pnt[maxn];
    int dp[maxn][maxm];
    
    void DP(int u)
    {
    	for(register int i=0;i<son[u].size();++i)//阶段,选取了第几组
    	{
    		int v=son[u][i];
    		DP(v);
    		for(register int t=m;t>=0;--t)//枚举背包已经放入的体积
    			for(register int j=t;j>=0;--j)
    				dp[u][t]=max(dp[u][t],dp[u][t-j]+dp[v][j]);
    	}
    	if(u!=0)//除超级根节点外,每个节点的选取都会获得pnt[u]的学分
    		for(register int t=m;t>0;--t)
    			dp[u][t]=dp[u][t-1]+pnt[u];
    }
    
    int main()
    {
    	scanf("%d%d",&n,&m);
    	int k;
    	for(register int i=1;i<=n;++i)
    	{
    		scanf("%d%d",&k,&pnt[i]);
    		prt[i]=k;
    	}
    	for(register int i=1;i<=n;++i)
    		son[prt[i]].push_back(i);
    	DP(0);
    	printf("%d",dp[0][m]);
    	return 0;
    }
    
  • 相关阅读:
    easyui tree loader用法
    mysql字符集
    mysql 内连接 左连接 右连接 外连接
    mysql 聚集函数和分组
    mysql 大数据量求平均值
    C++ 纯虚方法
    Windows xcopy
    服务端数据库的操作如何不阻塞
    分布式系统业务服务器的设计
    mysql 查询执行的流程
  • 原文地址:https://www.cnblogs.com/lizbaka/p/10246427.html
Copyright © 2011-2022 走看看