1. 程式人生 > >HDU 1520 淺談簡單樹形動態規劃

HDU 1520 淺談簡單樹形動態規劃

這裡寫圖片描述
世界真的很大
趁著早上還沒開始考試,悄咪咪地做一道樹形DP
input裡面沒讀出是多組資料,WA了兩發才發現orz
主要是感覺還是不是很熟悉,特別是對於樹形這一方面地問題
趁著NOIP之前趕緊地複習一下
就從這道水題開始吧

看題先:

description:

題目給出一棵樹,每個節點都有其權值。如果選擇了一個節點則不可以選擇其父節點,問能取得的最大值

input:

Employees are numbered from 1 to N. A first line of input contains a number N. 1 <= N <= 6 000. Each of the subsequent N lines contains the conviviality rating of the corresponding employee. Conviviality rating is an integer number in a range from -128 to 127. After that go T lines that describe a supervisor relation tree. Each line of the tree specification has the form:
L K
It means that the K-th employee is an immediate supervisor of the L-th employee. Input is ended with the line
0 0

output:

Output should contain the maximal sum of guests’ ratings.

題目讀起來就像是DP,考慮是在樹上的問題,所以考慮樹形DP
那麼考慮樹形DP的狀態設計,一般與子樹有關,即求出子樹的答案然後合併上去
考慮在合併的時候,會影響答案合併的狀態,就是子樹的根節點選或者不選了,選了的話當前節點就不能選,兩者的答案不一樣當然要分開統計
於是得出狀態設計 : f(i,0/1)
表示第i個子樹內,i這個點選或者不選的最大值
f(i,0) = sigma max(f(v,0),f(v,1)) + ai,這是由於只要根不選,子樹選不選都可以的緣故
f(i,1) = sigma f(v,0) ,這是由於根選了,所有子樹的根都不能選的緣故
然後就OK了

完整程式碼:

#include<stdio.h>
#include<cstring>
#include<algorithm>
using namespace std;

struct edge
{
    int v,last;
}ed[100010];

int n,num=0,S;
int a[100010],head[100010],f[100010][2],in[100010];

void init()
{
    num=0;
    memset(head,0,sizeof(head));
    memset(in,0,sizeof(in));
    memset(f,0,sizeof
(f)); } void add(int u,int v) { num++; ed[num].v=v; ed[num].last=head[u]; head[u]=num; } void dfs(int u,int fa) { f[u][1]=a[u]; for(int i=head[u];i;i=ed[i].last) { int v=ed[i].v; if(v==fa) continue ; dfs(v,u); f[u][0]+=max(f[v][1],f[v][0]); f[u][1]+=f[v][0]; } } int main() { while(scanf("%d",&n)!=EOF) { init(); for(int i=1;i<=n;i++) scanf("%d",&a[i]); for(int i=1;i<n;i++) { int u,v; scanf("%d%d",&u,&v); add(v,u),add(u,v); in[u]++; } scanf("\n0 0"); for(int i=1;i<=n;i++) if(!in[i]) { S=i; break ; } dfs(S,S); printf("%d\n",max(f[S][1],f[S][0])); } return 0; }

嗯,就是這樣