问题描述
有一棵 n 个节点的树,树上每个节点都有一个正整数权值。如果一个点被选择了,那么在树上和它相邻的点都不能被选择。求选出的点的权值和最大是多少?
输入格式
第一行包含一个整数 n 。
接下来的一行包含 n 个正整数,第 i 个正整数代表点 i 的权值。
接下来一共 n-1 行,每行描述树上的一条边。
输出格式
输出一个整数,代表选出的点的权值和的最大值。
样例输入
5
1 2 3 4 5
1 2
1 3
2 4
2 5
1 2 3 4 5
1 2
1 3
2 4
2 5
样例输出
12
样例说明
选择3、4、5号点,权值和为 3+4+5 = 12 。
数据规模与约定
对于20%的数据, n <= 20。
对于50%的数据, n <= 1000。
对于100%的数据, n <= 100000。
权值均为不超过1000的正整数。
- #include<iostream>
- #include<cmath>
- #include<cstring>
- using namespace std;
- #define MAX 1000000
- struct node
- {
- long v;
- node *next;
- }*head[MAX],tree[MAX];
- long n,ptr,dp[MAX][2];
- long vis[MAX],num[MAX];
- void initial()
- {
- ptr=1;
- memset(dp,0,sizeof(dp));
- memset(vis,0,sizeof(vis));
- memset(head,NULL,sizeof(head));
- }
- void addEdge(long a, long b)
- {
- tree[ptr].v=b;
- tree[ptr].next=head[a],head[a]=&tree[ptr++];
- tree[ptr].v=a;
- tree[ptr].next=head[b],head[b]=&tree[ptr++];
- }
- void tree_DP( long v)
- {
- if(vis[v])
- return;
- vis[v]=1;
- long i,j,k,tot=0,sum;
- node *p=head[v];
- while(p!=NULL)
- {
- if(!vis[p->v])
- {
- tree_DP(p->v);
- dp[v][1]+=dp[p->v][0];
- dp[v][0]+=max(dp[p->v][1],dp[p->v][0]);
- }
- p=p->next;
- }
- dp[v][1]+=num[v];
- }
- int main()
- {
- while(cin>>n)
- {
- initial();
- for(long i=1;i<=n;i++)
- cin>>num[i];
- long a,b;
- //while(cin>>a>>b)
- for( long i=0;i<n-1;i++)
- {
- cin>>a>>b;
- addEdge(a,b);
- }
- tree_DP(1);
- cout<<max(dp[1][0],dp[1][1])<<endl;
- }
- return 0;
- }
这是一道树形DP的题目
更多树形DP,可以去http://blog.csdn.net/hhaile/article/details/9621231 中去学习