zoukankan      html  css  js  c++  java
  • poj1155

    题意:给定一个树形图,节点数量3000。叶子节点是用户,每个用户如果能看上电视会交一定的电视费。看上电视的条件是从根到该用户的路径全部被修好,修每条边有一个费用。在不亏损(用户交钱总额>=修路总费用)的前提下,最多有多少人能看上电视。

    分析:树形dp。dp[u][i][j]表示对于u节点,只看其前i个儿子对应的子树,在这些子树中总共让j个用户看上电视,这样的最大利润是多少(可以为负值)。

    那么dp[u][i][j]=max(dp[u][i-1][j], dp[v][num[v][k] + dp[u][i - 1][j - k] - cost(u, v));其中v是u第i个儿子,num[v]表示以v为根的子树中总共有多少用户,cost(u,v)表示u到v这条边需要的花费。

    以上是非叶子节点的转移方法,对于叶子节点则稍有不同,直接赋值为该用户交的钱即可。

    #include <cstdio>
    #include <vector>
    using namespace std;
    
    #define D(x) 
    
    const int INF = 0x3f3f3f3f;
    const int MAX_N = (int)(3e3) + 10;
    
    int n, m;
    int money[MAX_N];
    vector<pair<int, int> > edge[MAX_N];
    int dp[MAX_N][MAX_N];
    int num[MAX_N];
    int sum[MAX_N];
    
    void input()
    {
        scanf("%d%d", &n, &m);
        for (int i = 1; i <= n - m; i++)
        {
            int k;
            scanf("%d", &k);
            for (int j = 0; j < k; j++)
            {
                int a, c;
                scanf("%d%d", &a, &c);
                edge[i].push_back(make_pair(a, c));
            }
        }
        for (int i = n - m + 1; i <= n; i++)
        {
            scanf("%d", &money[i]);
        }
    }
    
    void dfs(int u, int cost)
    {
        if (u > n - m)
        {
            dp[u][0] = 0;
            num[u] = 1;
            sum[u] = money[u];
            dp[u][1] = money[u];
            return;
        }
    
        num[u] = 0;
        sum[u] = 0;
        for (int i = 0; i < (int)edge[u].size(); i++)
        {
            int v = edge[u][i].first;
            int w = edge[u][i].second;
            dfs(v, w);
            num[u] += num[v];
            sum[u] += sum[v];
        }
        fill_n(dp[u], num[u] + 1, -INF);
        dp[u][0] = 0;
        for (int i = 0; i < (int)edge[u].size(); i++)
        {
            int v = edge[u][i].first;
            int w = edge[u][i].second;
            for (int j = num[u]; j >= 1; j--)
            {
                int limit = min(j, num[v]);
                for (int k = 1; k <= limit; k++)
                {
                    dp[u][j] = max(dp[u][j], dp[v][k] + dp[u][j - k] - w);
                }
            }
        }
    }
    
    int main()
    {
        input();
        dfs(1, 0);
        int ans = 0;
        for (int i = 0; i <= num[1]; i++)
        {
            if (dp[1][i] >= 0)
                ans = max(ans, i);
        }
        for (int i = 1; i <= n; i++)
        {
            for (int j = 0; j <= num[i]; j++)
            {
                D(printf("dp[%d][%d]=%d	", i, j, dp[i][j]));
            }
            D(puts(""));
        }
        printf("%d
    ", ans);
        return 0;
    }
    View Code
  • 相关阅读:
    Linux的命令、用户、权限管理
    Java中快捷键
    数组的学习
    Java中方法定义和调用的学习
    java中的标识符、修饰符、关键字
    MYSQL的学习
    JavaScript小白教程2
    navicat中选择utf-8时的困惑
    python小白教程
    英语单词
  • 原文地址:https://www.cnblogs.com/rainydays/p/4394708.html
Copyright © 2011-2022 走看看