1. 程式人生 > >沒有上司的晚會【樹狀DP】

沒有上司的晚會【樹狀DP】

> Description
  Ural大學有N個職員,編號為1~N。他們有從屬關係,也就是說他們的關係就像一棵以校長為根的樹,父結點就是子結點的直接上司。每個職員有一個快樂指數。現在有個週年慶宴會,要求與會職員的快樂指數最大。但是,沒有職員願和直接上司一起與會。


> Input
第一行一個整數N。(1<=N<=6000)
接下來N行,第i+1行表示i號職員的快樂指數Ri。(-128<=Ri<=127)
接下來N-1行,每行輸入一對整數L,K。表示K是L的直接上司。
最後一行輸入0,0。

> Output
輸出最大的快樂指數。


> Sample Input


7
1
1
1
1
1
1
1
1 3
2 3
6 4
7 4
4 5
3 5
0 0

> Sample Output
5


> 解題思路
根據題意,可以弄出一個樹狀結構:
在這裡插入圖片描述
s[i][0]表示不選序號為i的職員,相反,s[i][1]表示選序號為i的職員(的最大快樂指數)。因為(如圖)如果選了序號5,那就一定不能選3和4,就必須得選1、2、6、7;如果沒有選5,3和4選不選都無所謂,如果3和4選的話就不能選1、2、6、7了。
在這裡插入圖片描述
如這一幅圖(第一個數為選當前數,第二個數為不選)

然後就是領接表:f[i].x存直屬上司,f[i].to存這個上司的其中一個職員。f[i].next和h的陣列連用,把屬於h[i]中的上司i的所有職員連在了一起,看程式碼理解一下。。。

序號 1 2 3 4 5 6
head 2 4 6
f.x 3 3 4 4 5 5
f.to 1 2 6 7 4 3
f.next 0 1 0 3 0 5

> 程式碼

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
struct ooo
{
	int x,to,next;
}f[6005];
bool hh[6005]={0};
int h[6005],a[6005],s[6005][2];
int n,l,k,father;

void lil(int now)
{
	s[now][1]=a[now]; //如果選now當前數的話就加上當前數的快樂指數
	for(int i=h[now];i;i=f[i].next)//迴圈now的職員
	{
		lil(f[i].to);//遞迴
		s[now][1]+=s[f[i].to][0];//選當前數的話就加上不選他的職員的最大快樂值
		s[now][0]+=max(s[f[i].to][1],s[f[i].to][0]);
		//不然不選的話他的職員選不選都無所謂,當然選最大的那個
	}
}

int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++) scanf("%d",&a[i]);
	for(int i=1;i<=n-1;i++)
	{
		scanf("%d%d",&l,&k);
		f[i].x=k; f[i].to=l; 
		f[i].next=h[k]; h[k]=i;
		hh[l]=1;
	} //存數
	scanf("%d%d",&l,&k); 
	for(int i=1;i<=n;i++) if(hh[i]==0) {father=i; break;} //找出父節點
	lil(father);
	printf("%d",max(s[father][0],s[father][1]));
	return 0;
}