原題地址:http://poj.org/problem?id=2342spa
題目大意:code
上司和下屬不能同時參加派對,求參加派對的最大活躍值。blog
關係知足一棵樹,每一個人都有本身的活躍值(-128~127)it
求最大的活躍度。io
樹形DP入門題。入門
首先講解一下樹形DP,顧名思義,樹形DP必定是在樹上的DP,與普通的DP類似,具備兩個方向。function
1.根---->葉class
2.葉---->根搜索
其中第二種最爲經常使用。實現方法:從根節點開始DFS(深度優先搜索),一直搜索到葉節點,而後根據其特殊性質賦值。經過回溯更新到根節點。得出答案。方法
回過來講這道題。
首先是狀態。
這道題的DP狀態共兩維,第一維表示本身自己編號,第二維表示去或者不去。
即dp[i][j] j的取值爲0或1,1表示去,0表示不去。
最後的答案即爲根節點的狀態max(dp[root][0],dp[root][1]);
首先常規操做,建邊,找根節點。有向圖,咱們能夠經過統計入度和出度來判斷根節點和葉節點。
接下來是狀態轉移方程:
dp[x][1]+=dp[to][0];
dp[x][0]+=max(dp[to][0],dp[to][1]);
很好理解,x是上司,to是下屬,經過下屬來更新上司。
一個上司可能有多個下屬,可是這些下屬只能有一個上司,符合樹的定義。
若是這個上司去,那麼下屬只能不去,因此要加上全部的下屬不去的狀態。即dp[to][0]
若是上司不去,這個時候須要比較下屬去或者不去的大小。
有的同窗可能會問了,爲何不直接讓下屬去多好啊,一步貪心,至關於把樹進行了黑白染色,要麼黑的去,要麼白的去,比較一下大小不就行了?
我剛開始糾結了半天,後來發現了題中所給的條件。
關係知足一棵樹,每一個人都有本身的活躍值(-128~127)。
因爲有些員工過於矯情,去派對本身還不活躍,因此以前的貪心是錯誤的。
以後比較老總(根節點)去或者不去的大小,選擇較大值。
上代碼:
#include<cstdio> #include<algorithm>
using namespace std; int val[7000]; int indegree[7000]; int outdegree[7000]; struct edge { int to; int nxt; }eg[7000]; int head[7000]; int cnt = 1; void add(int x,int y) { eg[cnt].to = y; eg[cnt].nxt = head[x]; head[x] = cnt++; } int dp[7000][3]; void dfs(int x) { if(outdegree[x]==0) { dp[x][1] = val[x]; return ; } for(int i = head[x];i;i=eg[i].nxt) { int to = eg[i].to; dfs(to); dp[x][1]+=dp[to][0]; dp[x][0]+=max(dp[to][0],dp[to][1]); } } int main() { int n; scanf("%d",&n); for(int i = 1;i<=n;i++) { scanf("%d",&val[i]); dp[i][1] = val[i]; } for(int i = 1;i<=n;i++) { int x,y; scanf("%d%d",&x,&y); if(x==0&&y==0) { break; } indegree[x]++; outdegree[y]++; add(y,x); } int root; for(int i = 1;i<=n;i++) { if(indegree[i]==0) { root = i; } } dfs(root); printf("%d",max(dp[root][0],dp[root][1])); }