• 洛谷P1273 有线电视网【树形dp】


    题目https://www.luogu.org/problemnew/show/P1273

    题意:一棵树,叶子节点是用户,每天边有一个权值表示花费,每一个用户有一个值表示他们会交的钱。

    问在不亏本的情况下,最多可以选择多少个用户,让他们得到从根节点(1)发送出的服务。

    思路:本来很天真的以为是先dfs处理出每个叶子节点到根的净利润,然后背包。【太傻逼了】

    但是同一棵子树上的节点共用了一段路径,这里是不用重复算的。

    所以要树形dp,$dp[i][j]$表示以$i$为根的子树上选了$j$个节点。

    $dp[i][j] = max(dp[i][j], dp[i][j-k]+dp[son][k]-e.w)$

    $j$的范围是$i$的子孙数,这个需要dfs的时候统计,$k$的范围是$son$这棵子树的大小。

     1 #include<cstdio>
     2 #include<cstdlib>
     3 #include<map>
     4 #include<set>
     5 #include<cstring>
     6 #include<algorithm>
     7 #include<vector>
     8 #include<cmath> 
     9 #include<stack>
    10 #include<queue>
    11 #include<iostream>
    12 
    13 #define inf 0x3f3f3f3f
    14 using namespace std;
    15 typedef long long LL;
    16 typedef pair<int, int> pr;
    17 
    18 int n, m;
    19 const int maxn = 3005;
    20 int head[maxn], tot;
    21 struct edge{
    22     int to, w, nxt;
    23 }e[maxn];
    24 int pay[maxn];
    25 int dp[maxn][maxn];
    26 
    27 void add(int x, int y, int c)
    28 {
    29     e[++tot].to = y;
    30     e[tot].w = c;
    31     e[tot].nxt = head[x];
    32     head[x] = tot;
    33 }
    34 
    35 int dfs(int now)
    36 {
    37     if(now > n - m){
    38         dp[now][1] = pay[now];
    39         return 1;
    40     }
    41     int sum = 0, son = 0;
    42     for(int i = head[now]; i; i = e[i].nxt){
    43         int to = e[i].to;
    44         //printf("%d %d
    ", now, e[i].to);
    45         son = dfs(to);
    46         sum += son;
    47         for(int j = sum; j > 0; j--){
    48             for(int k = 1; k <= son; k++){
    49                 if(j >= k)dp[now][j] = max(dp[now][j], dp[now][j - k] + dp[to][k] - e[i].w);
    50             }
    51         }
    52     }
    53     return sum;
    54 }
    55 
    56 int main()
    57 {
    58     memset(dp, ~0x3f, sizeof(dp));
    59     memset(head, 0, sizeof(head));
    60     scanf("%d%d", &n, &m);
    61     for(int i = 1; i <= n - m; i++){
    62         int k;
    63         scanf("%d", &k);
    64         while(k--){
    65             int a, c;
    66             scanf("%d%d", &a, &c);
    67             add(i, a, c);
    68         }
    69         dp[i][0] = 0;
    70     }
    71     for(int i = n - m + 1; i <= n; i++){
    72         scanf("%d", &pay[i]);
    73         dp[i][0] = 0;
    74     }
    75     dfs(1);
    76     for(int i = m; i > 0; i--){
    77         if(dp[1][i] >= 0){
    78             printf("%d
    ", i);
    79             break;
    80         }
    81     }
    82 }
  • 相关阅读:
    Notebook ++ 设置护眼背景
    python 设置 excel 单元格颜色填充和字体效果
    python 设置 Excel 单元格边框线的各种风格
    python 对 excel sheet 的插入、复制、删除、重命名、设置标签颜色操作
    python 利用插入空行的方式制作工资条表格
    python 更新 openpyxl 到 3.0
    python 模拟 excel 宏、VBA 制作工资条表格
    Windows 系统
    python-pptx 实践 6.2:气泡图
    python-pptx 实践 6.1:添加五种基本图形(柱形图、折线图、饼图、条形图、散点图)
  • 原文地址:https://www.cnblogs.com/wyboooo/p/11084698.html
Copyright © 2020-2023  润新知