• Nowcoder51179.选课(树形背包)


    学校实行学分制。
    每门的必修课都有固定的学分,同时还必须获得相应的选修课程学分。
    学校开设了 N 门的选修课程,每个学生可选课程的数量 M 是给定的。
    学生选修了这 M 门课并考核通过就能获得相应的学分。
    在选修课程中,有些课程可以直接选修,有些课程需要一定的基础知识,必须在选了其他的一些课程的基础上才能选修。
    例如《Windows程序设计》必须在选修了《Windows操作基础》之后才能选修。
    我们称《Windows操作基础》是《Windows程序设计》的先修课。
    每门课的直接先修课最多只有一门。
    两门课可能存在相同的先修课。
    你的任务是为自己确定一个选课方案,使得你能得到的学分最多,并且必须满足先修条件。
    假定课程之间不存在时间上的冲突。

    注意滚动数组转移时的细节。

    //f(i,j)表示在节点i的子树内选择j个节点所能得到的最大学分
    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=1010;
    typedef long long ll;
    ll f[maxn][maxn][2]; 
    int e[maxn];
    int a[maxn];
    vector<int> g[maxn];
    int n,m;
    int rt=0;
    int size[maxn];
    void dfs (int x) {
    	size[x]=1;
    	f[x][1][1]=a[x];
    	int k=0;
    	for (int y:g[x]) {
    		dfs(y);
    		for (int i=0;i<=n;i++) f[x][i][k]=0; 
    		for (int i=min(m,size[x]);i>=1;i--) {
    			for (int j=min(m,size[y]);j>=0;j--) {
    				if (i+j<=m)
    					f[x][i+j][k]=max(f[x][i+j][k],f[x][i][k^1]+f[y][j][e[y]]);
    			}
    		}
    		size[x]+=size[y];
    		k^=1;
    	}
    	e[x]=(k^1);
    }
    int main () {
    	scanf("%d%d",&n,&m);
    	m++;
    	for (int i=1;i<=n;i++) {
    		int x;
    		scanf("%d%d",&x,&a[i]);
    		g[x].push_back(i);
    	}
    	dfs(0);
    	//for (int i=1;i<=m;i++) printf("%d
    ",f[0][i]);
    	printf("%lld
    ",f[0][m][e[0]]);
    }
  • 相关阅读:
    frame、center和bounds
    UILabel
    UIColor
    Url_Filter(Code)
    listView介绍
    C# 常用正则
    C++指针的概念
    指针所具有的四个要素:
    windows_sendEmail
    工作笔记
  • 原文地址:https://www.cnblogs.com/zhanglichen/p/14605813.html
Copyright © 2020-2023  润新知