luogu P1273 有线电视网 树上背包dp

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 3030;
int h[N], e[N], ne[N], w[N], idx;
int val[N];
int n, m;//n为整个有线电视网的结点总数,m为用户终端的数量
int dp[N][N];//dp[i][j]表示i节点,选j个用户,能得到的钱的最大值
void add(int a, int b, int c)
{
	e[idx] = b;
	w[idx] = c;
	ne[idx] = h[a];
	h[a] = idx++;
}
int dfs(int u)
{
	if(u > n - m)//u为用户终端
	{
		dp[u][1] = val[u];
		return 1;
	}
	int sum = 0;
	for(int k = h[u]; k !=-1; k = ne[k])
	{
		int v = e[k];
		int t = dfs(v);
		sum += t;
		for(int j = sum; j > 0; j --)
			for(int i = 1; i <= t; i ++)
				if(j - i >= 0)//因为是从下往上递归,所以之前的边都减过了,减去当前的边
					dp[u][j] = max(dp[u][j], dp[u][j - i] + dp[v][i] - w[k]);
	}
	return sum;
}
int main()
{
	memset(dp,~0x3f,sizeof(dp));
	memset(h, -1, sizeof h);
	cin >> n >> m;
	for(int u = 1; u <= n - m; u ++)
	{
		int size;
		cin >> size;
		for(int j = 1; j <= size; j ++)
		{
			int b, c;
			cin >> b >> c;
			add(u, b, c);
		}
	}
	for(int i = n - m + 1; i <= n; i ++)
		cin >> val[i];
	for(int i = 1; i <= n; i ++)
		dp[i][0] = 0;//选0个用户的花费肯定是0啦
	dfs(1);
	for(int i = m; i >= 1; i --)
		if(dp[1][i] >= 0)
		{
			cout << i << endl;
			break;
		}
	return 0;
}

posted @ 2020-05-03 19:35  晴屿  阅读(77)  评论(0编辑  收藏  举报