zoukankan      html  css  js  c++  java
  • RQNOJ 188 购物问题:树形dp

    题目链接:https://www.rqnoj.cn/problem/188

    题意:

      商场以超低价格出售n个商品,购买第i个商品所节省的金额为w[i]。

      为了防止亏本,有m对商品是不能同时买的。但保证商品关系不出现环,不会出现如:(1,2) , (2,4) , (1,4)。

      问你最多能节省的金额。

    题解:

      简直和POJ 2342 Anniversary party像极了(*/ω\*)

      将不能同时买的商品间连一条无向边。

      所以子节点和父节点不能同时选。

      唯一不同的是POJ是一棵树,而这道题是一片森林。需要对于每一棵树分别求dp,然后求和。

      表示状态:

        dp[i][j] = max discount

        i:考虑到第i个商品(节点i)

        j:是否选节点i (j == 0 / 1)

      找到答案:

        ans = ∑ max(dp[root[i]][0],dp[root[i]][1]) (root[i]为每棵树的根)

      如何转移:

        dp[i][1] = sigma dp[son][0]     (选父节点)

        dp[i][0] = sigma max dp[son][0/1] (不选父节点)

        在dfs中:

          dp[now][1] = w[i]

          dfs(nex...)

          dp[par][1] += dp[now][0]

          dp[par][0] += max(dp[now][0], dp[now][1])

      边界条件:

        dp[i][1] = w[i] (至少选自己)

        dp[i][0] = 0

    AC Code:

     1 // state expression:
     2 // dp[i][j] = max discount
     3 // i: considering ver i
     4 // j: whether to select j ver
     5 //
     6 // find the answer:
     7 // max dp[root][0/1]
     8 //
     9 // transferring:
    10 // dp[i][1] = sigma dp[son][0]
    11 // dp[i][0] = sigma max dp[son][0/1]
    12 // dfs:
    13 // dp[now][1] = w[i]
    14 // dfs(nex...)
    15 // dp[par[now]][1] += dp[now][0]
    16 // dp[par[now]][0] += max(dp[now][0], dp[now][1])
    17 //
    18 // boundary:
    19 // dp[i][1] = w[i]
    20 // dp[i][0] = 0
    21 #include <iostream>
    22 #include <stdio.h>
    23 #include <string.h>
    24 #include <vector>
    25 #define MAX_N 1005
    26 
    27 using namespace std;
    28 
    29 int n,m;
    30 int a,b;
    31 int ans;
    32 int w[MAX_N];
    33 int dp[MAX_N][2];
    34 bool vis[MAX_N];
    35 vector<int> edge[MAX_N];
    36 
    37 void read()
    38 {
    39     cin>>n>>m;
    40     for(int i=1;i<=n;i++)
    41     {
    42         cin>>w[i];
    43     }
    44     for(int i=0;i<m;i++)
    45     {
    46         cin>>a>>b;
    47         edge[a].push_back(b);
    48         edge[b].push_back(a);
    49     }
    50 }
    51 
    52 void dfs(int now,int par)
    53 {
    54     vis[now]=true;
    55     dp[now][1]=w[now];
    56     for(int i=0;i<edge[now].size();i++)
    57     {
    58         int temp=edge[now][i];
    59         if(temp!=par) dfs(temp,now);
    60     }
    61     if(par!=-1)
    62     {
    63         dp[par][1]+=dp[now][0];
    64         dp[par][0]+=max(dp[now][0],dp[now][1]);
    65     }
    66 }
    67 
    68 void solve()
    69 {
    70     memset(dp,0,sizeof(dp));
    71     memset(vis,false,sizeof(vis));
    72     ans=0;
    73     for(int i=1;i<=n;i++)
    74     {
    75         if(!vis[i])
    76         {
    77             dfs(i,-1);
    78             ans+=max(dp[i][0],dp[i][1]);
    79         }
    80     }
    81 }
    82 
    83 void print()
    84 {
    85     cout<<ans<<endl;
    86 }
    87 
    88 int main()
    89 {
    90     read();
    91     solve();
    92     print();
    93 }
  • 相关阅读:
    优化C/C++代码的小技巧
    闭包,看这一篇就够了——带你看透闭包的本质,百发百中
    7215:简单的整数划分问题
    常见问题最佳实践三:服务启动顺序
    JAVA 用分苹果来理解本题
    arcgis访问格式
    墨卡托投影
    C# 从DataTable中取值
    Base64编码的字符串与图片的转换 C#
    墨卡托投影实现
  • 原文地址:https://www.cnblogs.com/Leohh/p/7461347.html
Copyright © 2011-2022 走看看