洛谷P1352
阿新 • • 發佈:2018-12-13
本題很巧妙。
我們這樣去構想整個樹,對於每個人只有去和不去兩種情況,如果 A 去了,A的手下必定不去,反之如果A不去,那麼A的手下可以去,也可以不去,既然只有兩種情況我們就可以構造一個狀態轉移方程:設定兩個Dp 一個記錄當前節點不去時的總快樂度,一個記錄去的話的總快樂度
Dp1[x](假設A去舞會)+= Dp2[x.to] ;
Dp2[x](假設A沒去) += max( Dp1[x.to], Dp2[x.to] )
那麼整個轉移方程出來了,我們就可以開始構造整個樹了
把子節點設為下屬,父節點設為上司,然後還是後序遍歷的思路,找出一個最大值。
以下就是 AC 程式碼
#include<iostream> #include<cstdio> #include<cstring> using namespace std; const int maxn = 1e5+5; int head[maxn],tot; int num[maxn]; struct node { int nxt,to; }ed[maxn]; int vis[maxn]; int dp[maxn][2]; void add(int u,int v) { ed[++tot].to = v; ed[tot].nxt = head[u]; head[u] = tot; } void dfs(int s) { dp[s][0] = 0; dp[s][1] = num[s]; for(int i=head[s];~i;i=ed[i].nxt) { int to = ed[i].to; dfs(to); dp[s][0] += max(dp[to][0],dp[to][1]); dp[s][1] += dp[to][0]; } return ; } int main() { int n; scanf("%d",&n); tot = 1; memset(vis,0,sizeof vis); memset(head,-1,sizeof head); for(int i=1;i<=n;i++) { scanf("%d",&num[i]); } for(int i=1;i<=n;i++) { int x,y; scanf("%d%d",&x,&y); add(y,x); //注意這裡建連結的方式,父節點設為上司 vis[x] = 1; } int rt; for(int i=1;i<=n;i++) { if(!vis[i]) { rt = i; break; } } dfs(rt); printf("%d\n",max(dp[rt][0],dp[rt][1])); return 0; }