洛谷 P1273 有线电视网
url: https://www.luogu.com.cn/problem/P1273
tag:
动态规划,树形DP,背包DP
思路:
用 f[u][j]
表示第u个节点选择j个用户时的盈利数。使用分组背包的思想。状态转移方程为
f[u][k] = max(f[u][k], f[u][k - l] + f[j][l] - w[i])
其中w表示如果将节点j接入时的成本。最后因为是求不亏本时最多可以观看转播的用户数,所以从m开始向下循环,直到找到第一个盈利大于等于0的然后输出用户数即可。
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 3030;
int h[N], e[N * 2], ne[N * 2], w[N * 2], idx;
int n, m;
int p[N];
int s[N];
int f[N][N];
void dfs(int u, int fa)
{
if (u > n - m) f[u][1] = p[u], s[u] = 1;
for (int i = h[u]; ~i; i = ne[i])
{
int j = e[i];
if (j == fa) continue;
dfs(j, u);
s[u] += s[j];
for (int k = m; k >= 0; k --)
{
for (int l = 1; l <= min(k, s[j]); l ++)
{
f[u][k] = max(f[u][k], f[u][k - l] + f[j][l] - w[i]);
}
}
}
}
void add(int a, int b, int c)
{
e[idx] = b;
ne[idx] = h[a];
w[idx] = c;
h[a] = idx ++;
}
int main()
{
memset(h, -1, sizeof h);
memset(f, -0x3f, sizeof f);
cin >> n >> m;
for (int i = 1; i <= n - m; i ++)
{
int k;
cin >> k;
for (int j = 0; j < k; j ++)
{
int a, b;
cin >> a >> b;
add(i, a, b), add(a, i, b);
}
}
for (int i = n - m + 1; i <= n; i ++) cin >> p[i];
for (int i = 1; i <= n; i ++) f[i][0] = 0;
dfs(1, 0);
for (int i = m; i >= 0; i --)
{
if (f[1][i] >= 0)
{
cout << i;
break;
}
}
return 0;
}
当前页面是本站的「Google AMP」版。查看和发表评论请点击:完整版 »