zoukankan      html  css  js  c++  java
  • POJ 1155 TELE(树形DP)

    题意:

    有一个电视台广播节目,广播的网络用一棵树表示,节点1表示电台,叶子结点表示用户,用户愿意付一定的钱去收看这个节目,

    从非叶子结点到其他结点需要一定的费用(即从中继点到另一个中继点需要一些钱),问最后在不亏本的情况下,最多能使多少人收看到节目。

    思路:

    1. 和 POJ 1947 类似的题目,dp[u][i] 表示 u 节点为根,保留 i 个节点的最大盈利。

    2. dp[u][i] = max(dp[u][i], dp[u][i-j] + dp[v][j] - w)

    3. 如果叶子节点选定,则从叶子到根的一条路径上面的节点都应该被选定,所以初始化的时候赋值为 -INFS,只有当dp[叶子][i] 合法时,dp[rt][]才能合法。

    4. sum[u] 表示以 u 为根节点的子树能覆盖多少个有效用户。算是解题中的一点优化。

    #include <iostream>
    #include <algorithm>
    using namespace std;
    
    const int MAXN = 3010;
    const int INFS = 0x3fffffff;
    
    structedge {
        int v, c;
        edge* next;
    } *V[MAXN], ES[MAXN * 3];
    
    int EC, N, M, sum[MAXN], dp[MAXN][MAXN];
    
    void addedge(int u, int v, int c)
    {
        ES[++EC].next = V[u];
        V[u] = ES + EC; 
        V[u]->v = v, V[u]->c = c;
    }
    
    void initdata()
    {
        for (int i = 1; i <= N; ++i)
        {
            dp[i][0] = 0;
            for (int j = 1; j <= M; ++j)
                dp[i][j] = -INFS;
        }
    
        EC = 0;
        memset(V, 0, sizeof(V));
    
        for (int i = 1; i <= N - M; ++i)
        {
            int k, a, b;
            scanf("%d", &k);
            for (int j = 0; j < k; ++j)
            {
                scanf("%d %d", &a, &b);
                addedge(i, a, b);
                addedge(a, i, b);
            }
        }
    
        memset(sum, 0, sizeof(sum));
        for (int i = N - M + 1; i <= N; ++i)
            scanf("%d", &dp[i][1]), sum[i] = 1;
    }
    
    void treedp(int u, int f)
    {
        for (edge* e = V[u]; e; e = e->next)
        {
            if (e->v == f)
                continue;
    
            treedp(e->v, u);
            sum[u] += sum[e->v];
    
            for (int i = sum[u]; i >= 1; --i)
                for (int j = 1; j <= i; ++j)
                    if (dp[u][i-j] != -INFS && dp[e->v][j] != -INFS)
                        dp[u][i] = max(dp[u][i], dp[u][i-j] + dp[e->v][j] - e->c);
        }
    }
    
    int main()
    {
        while (scanf("%d %d", &N, &M) != EOF)
        {
            initdata();
            treedp(1, 0);
    
            int i;
            for (i = M; i >= 0; --i)
                if (dp[1][i] >= 0)
                    break ;
    
            printf("%d\n", i);
        }
        return 0;
    }
  • 相关阅读:
    HTTP的OPTIONS请求方法
    K8s -- DaemonSet
    Nginx 变量漫谈(二)
    Nginx 变量漫谈(一)
    通俗地讲,Netty 能做什么?
    CSP AFO后可以公开的情报
    AT1219 歴史の研究
    LuoguP4165 [SCOI2007]组队
    CF708C Centroids(树形DP)
    CF208E Blood Cousins(DSU,倍增)
  • 原文地址:https://www.cnblogs.com/kedebug/p/2919069.html
Copyright © 2011-2022 走看看