1. 程式人生 > >RQNOJ 188 購物問題:樹形dp

RQNOJ 188 購物問題:樹形dp

cin href ++ problem expr ive 子節點 col sco

題目鏈接: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