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 }
原文地址:https://www.cnblogs.com/Leohh/p/7461347.html