zoukankan      html  css  js  c++  java
  • CTSC1998 选课(背包类树形Dp)

    题意:

    给出 n 节课的先修课号以及学分(先修课号指的是在学习某节课时先需要学习的课程),求学 m 节课的最大学分。

    细节:

    1、对于课程 a 其先修课号为 b ,对于课程 b 其先修课号为 c ,则需要学 a 的方式必须为先学 c 在学 b
    2、可能存在多门课程没有先修课号。

    分析:

    题目给出的先修课号是唯一的,所以我们可以将这种依赖关系构建成一棵树,所以对于每个节点的学分之和就是为从根节点到其的简单路径,所以对于每个节点相当于一个背包。

    所以状态就是:dp[u][j] 表示以 u 为根的子树选了 j 门课所获得最大学分

    转移就是:dp[u][j] = max( dp[u][j] , dp[u][j-k] + dp[v][k] )
    其中 dp[u][1] = dist[u] , 1 ≤ j ≤ size[u] , 0≤k≤min( size[v] , j-1)

    代码:

    #include <bits/stdc++.h>
    #define MAXN 305
    using namespace std;
    
    int f[MAXN][MAXN], dist[MAXN], size[MAXN], n, m;
    vector <int> G[MAXN];
    
    void build(int u){
    	size[u]=1;
    	for (int i=0; i<G[u].size(); i++){
    		int v=G[u][i];
    		build(v);
    		size[u]+=size[v];
    	}
    
    }
    
    void solve(int u){
    	f[u][1]=dist[u];
    	for (int i=0; i<G[u].size(); i++){
    		int v=G[u][i];
    		solve(v);
    		for (int j=min(size[u], m+1); j>=2; j--)
    			for (int k=0; k<=min(size[v], j-1); k++)
    				f[u][j]=max(f[u][j], f[u][j-k]+f[v][k]); 
    	}
    }
    
    int main(){
    	scanf("%d%d", &n, &m);
    	for (int i=1, x; i<=n; i++){
    		scanf("%d%d", &x, &dist[i]);
    		G[x].push_back(i);
    	}
    	memset(f, 0, sizeof f);
    	build(0);
    	solve(0);
    	printf("%d\n", f[0][m+1]);
    	return 0;
    }
    
  • 相关阅读:
    Codeforces Round448 D
    Codeforces Round448 C Square Subsets
    hdu6006
    2017计蒜客计算之道初赛第六场 微软大楼设计方案(困难)
    UVA 12105 Bigger is Better
    Codeforce 55D Beautiful numbers
    4月补题
    C++小技巧之CONTAINING_RECORD
    Codeforces #380 div2 E(729E) Subordinates
    Codeforces #380 div2 D(729D) Sea Battle
  • 原文地址:https://www.cnblogs.com/xiannvzuimei/p/9961214.html
Copyright © 2011-2022 走看看