洛谷P2014 [CTSC1997]选课

\(\large{题目链接}\)
\(\\\)
\(\Large{Solution: } \large{一道树形背包的题目,还是有所启示的。\\首先,注意到题目中可能有多棵树,不好进行\text{DFS}先建一个超级原点0,链接所有树根。\\设f[i][j]表示以i为根的树里选j个点的最大值,然后用子树更新根即可。\\注意在这段代码中}\)
\(\quad \quad \quad \quad \quad \quad\) \(\\\)
\(\quad \quad \quad \quad \quad \quad\) \(\large{要用选的选的个数少的答案去更新选的多的,所以j要倒序。\\最后,输出是f[0][m+1]。}\)
\(\quad \quad \quad \quad \quad \quad\)
\(\\\)
\(\Large\textbf{Code: }\)

#include <bits/stdc++.h>
#define gc() getchar() 
#define LL long long
#define rep(i, a, b) for (int i = (a); i <= (b); ++i)
#define _rep(i, a, b) for (int i = (a); i >= (b); --i)
using namespace std;
const int N = 305;
int n, m, cnt, head[N], size[N], f[N][N];

struct Edge {
	int to, next;
}e[N << 1];

inline int read() {
	int x = 0;
	char ch = gc();
	while (!isdigit(ch)) ch = gc();
	while (isdigit(ch)) x = x * 10 + ch - '0', ch = gc();
	return x; 
}

inline void dfs1(int x) {
	size[x] = 1;
	for (int i = head[x]; i ; i = e[i].next) {
		int u = e[i].to;
		dfs1(u);
		size[x] += size[u];
	}
}

inline void dfs2(int x) {
	for (int i = head[x]; i ; i = e[i].next) {
		int u = e[i].to;
		dfs2(u);
		for (int j = size[x]; j >= 1; --j) 
			for (int k = 0; k < j; ++k)
				f[x][j] = max(f[x][j], f[x][j - k] + f[u][k]);
	}
}

inline void add(int x, int y) {
	e[++cnt].to = y;
	e[cnt].next = head[x];
	head[x] = cnt;
}

int main() {
	n = read(), m = read();
	int x;
	rep(i, 1, n) x = read(), f[i][1] = read(), add(x, i);
	dfs1(0);
	dfs2(0);
	printf("%d\n", f[0][m + 1]);
	return 0;
}

猜你喜欢

转载自www.cnblogs.com/Miraclys/p/12576547.html