算法训练 结点选择

<span style="font-family: 微软雅黑, 黑体, 宋体; background-color: rgb(255, 255, 255);">问题描述</span>
<span style="text-indent: 2em; background-color: rgb(255, 255, 255);"><span style="white-space: pre;">	</span>有一棵 n 个节点的树,树上每个节点都有一个正整数权值。如果一个点被选择了,那么在树上和它相邻的点都不能被选择。求选出的点的权值和最大是多少?</span>
输入格式

第一行包含一个整数 n 。

接下来的一行包含 n 个正整数,第 i 个正整数代表点 i 的权值。

接下来一共 n-1 行,每行描述树上的一条边。

输出格式
输出一个整数,代表选出的点的权值和的最大值。
样例输入
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的正整数。

节点数目多边少采用邻接表。

dp[i][0]表示该节点不被选择,dp[i][1]表示该结点被选择。

dp[u][1]+=dp[v][0];//选择了u结点,则与它邻接的结点不选。

dp[u][0]+=max(dp[v][0],dp[v][1]);不选择u结点,则与它邻接的结点选择结果最大的。

#include <iostream>
using namespace std;
/* run this program using the console pauser or add your own getch, system("pause") or input loop */
typedef struct node{
	int adjvex;
	node* next;
}EdgeNode;

typedef struct {
	int value;
	EdgeNode* firstedge;
}VertexNode;

void add(int a,int b, VertexNode* adjlist){
	EdgeNode* node = new EdgeNode;
	node->next = adjlist[a-1].firstedge;
	node->adjvex = b-1;
	adjlist[a-1].firstedge = node;
}

void treedp(int u,VertexNode* adjlist,int** dp,int* vis){
	vis[u] = 1;
	EdgeNode* p = adjlist[u].firstedge;
	while(p){
		int v = p->adjvex;
		if(!vis[v]){
			treedp(v,adjlist,dp,vis);
			dp[u][1]+=dp[v][0];
			dp[u][0]+=max(dp[v][1],dp[v][0]);
		}
		p = p->next;
	}
}

int main() {
	int n;
	 cin>>n;
	 VertexNode* adjlist;
	 adjlist = new VertexNode[n];
	 for(int i =  0;i<n; i++){
	 	cin>>adjlist[i].value;
	 	adjlist[i].firstedge = NULL;
	 }
	 int* father = new int[n+1]();
	 int root = 0;
	 for(int i = 0; i<n-1; i++){
	 	int a,b;
	 	cin>>a>>b;
	 	add(a,b,adjlist);
	 	add(b,a,adjlist);
	 	father[b] = a;
	 	root = a;
	 }
	 /*
	 for(int i = 0; i<n; i++){
	 	EdgeNode* p = adjlist[i].firstedge;
	 	cout<<i<<" ";
	 	while(p!=NULL){
	 		cout<<p->adjvex<<" ";
	 		p = p->next;
		 }
		 cout<<endl;
	 }
	 */
	 int** dp = new int*[n];
	 for(int i = 0;i<n; i++){
	 	dp[i] = new int[2];
	 	dp[i][0] = 0;
	 	dp[i][1] = adjlist[i].value;
	 }
	 while(father[root]){
	 	root = father[root];
	 }
	 int* vis = new int[n](); 
	 treedp(root-1,adjlist,dp,vis);
	 cout<<max(dp[root-1][0],dp[root-1][1])<<endl;
	return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值