RQNOJ 188 购物问题:树形dp
Posted Leohh
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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 }
以上是关于RQNOJ 188 购物问题:树形dp的主要内容,如果未能解决你的问题,请参考以下文章