Miraclys

一言(ヒトコト)

洛谷P1273 有线电视网

\(\large{题目链接}\)
\(\\\)
\(\Large\textbf{Solution: } \large{很显然的树上背包,可以发现题目中并没有给出转播站的范围,所以容易想到转移方程f_{i,j}表示在i的子树中选了j个终端,当然这个值越大越好。}\)

\(\Large\textbf{Summary: } \large{A掉之后看题解,发现子树大小统计直接维护dfs就好了,我咋没想到,还是太菜了。。。}\)
\(\\\)
\(\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 = 3e3 + 5;
int n, m, cnt, head[N], a[N], f[N][N], size[N];

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

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

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

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

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

int main() {
	ios::sync_with_stdio(false);
	memset(f, ~0x3f, sizeof (f));
	n = read(), m = read();
	int t = n - m, c, x, y;
	for (int i = 1; i <= t; ++i) {
		c = read();
		while (c--) {
			x = read(), y = read();
			add(i, x, y);
		}
	}
	dfs(1);
	rep(i, n - m + 1, n) a[i] = read();
	rep(i, 1, n) f[i][0] = 0;
	dfs2(1);
	_rep(i, m, 0) if (f[1][i] >= 0) { cout << i << endl; return 0; } 
}
posted @ 2020-03-28 13:25  Miraclys  阅读(86)  评论(0编辑  收藏  举报

关于本博客样式

部分创意和图片借鉴了

BNDong

的博客,在此感谢