Hekyのblog

洛谷 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」版。查看和发表评论请点击:完整版 »