选课

https://loj.ac/problem/10154

题目描述

  给出(n)门课及其先修课,每门课有一定学分,求选(m)门课能获得的最大学分。

思路

  由于原图可能是森林,可以先建一个虚根(0)号节点。我们考虑用(f[i][j])表示以(i)为根的子树的选(j)门课能获得的最大学分,并且(i)这门课必选,那么对于(f[i][j]),其答案就是在每个子树中分别选(k)门课和其他子树中选(j-k)门课的答案。

代码

#include <bits/stdc++.h>
using namespace std;

vector<int>son[110];
int n,m,f[110][110],a[110];
void dfs(int u)
{
	f[u][0]=0;
	for(int i=0;i<son[u].size();i++)
	{
		int v=son[u][i];
		dfs(v);
		for(int j=n;j>=0;j--)
			for(int k=j;k>=0;k--)
				f[u][j]=max(f[u][j],f[u][j-k]+f[v][k]);
	}
	if(u)
		for(int i=n;i>=1;i--)
			f[u][i]=f[u][i-1]+a[u];
}

int read()
{
	int res=0,w=1;
	char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){res=(res<<3)+(res<<1)+(ch^48);ch=getchar();}
	return res*w;
}
void write(int x)
{
	if(x<0){putchar('-');x=-x;}
	if(x>9)write(x/10);
	putchar(x%10+'0');
}
void writeln(int x)
{
	write(x);
	putchar('
');
}

int main() 
{
	m=read(),n=read();
	for(int i=1;i<=m;i++)
	{
		int x=read();a[i]=read();
		son[x].push_back(i);
	}
	dfs(0);
	writeln(f[0][n]);
}
原文地址:https://www.cnblogs.com/fangbozhen/p/11838011.html