有一棵 n 个节点的树,树上每个节点都有一个正整数权值。如果一个点被选择了,那么在树上和它相邻的点都不能被选择。求选出的点的权值和最大是多少?
第一行包含一个整数 n 。
接下来的一行包含 n 个正整数,第 i 个正整数代表点 i 的权值。
接下来一共 n-1 行,每行描述树上的一条边。
1 2 3 4 5
1 2
1 3
2 4
2 5
对于20%的数据, n <= 20。
对于50%的数据, n <= 1000。
对于100%的数据, n <= 100000。
权值均为不超过1000的正整数。
一开始看到这道题我是满脸蒙蔽的!
WTF???
100000个点???WTF???
然后百度了解题方法结果发现所有的代码如出一辙!但是就是没有一个有比较全面的注释,有一个室友注释但关键部分就是没搞懂就是这棵树到底是怎么存的...绞尽脑汁就是感觉还差了一点的样子...于是准备暂时放下这道题去看看其他的...结果(划重点)我在一个求最短路的题目的解法中看到了类似的存储结构然后顺藤摸瓜抓住了关键点---链式前向星 重点!!
在正式介绍链式前向星之前我们先了解一下前向星:
前向星一种数据结构,以储存边的方式来存储图。构造方法如下:读入每条边的信息,将边存放在数组中,把数组中的边按照起点顺序排序,前向星就构造完了。通常用在点的数目太多,或两点之间有多条弧的时候。一般在别的数据结构不能使用的时候才考虑用前向星。除了不能直接用起点终点定位以外,前向星几乎是完美的
以上是博主百度的结果,简单来说前向星就是一种只存储边的信息(起点,终点,权重)的一种存储结构,对于图一般有两种存储结构,邻接矩阵和邻接表,对于邻接矩阵而言,花费的空间实在是太大而且会造成很大的空间浪费所以在图中的点很多的时候这种方法就没有了用武之地,而对于邻接表过程实现有点复杂...而前向星是一个比较均衡的存储结构.
但是前向星由于将边的按照一定的方式排序,所以时间开支比较大,这个时候链式前向星就出来了.
链式前向星又称为邻接表的静态建表方式,其最开始确实是基于前向星,是以提高前向星的构造效率为目的设计的存储方式,最终演变成了一个变形的邻接表这一数据结构。链式前向星采用数组模拟链表的方式实现邻接表的功能(数组模拟链表的主要方式就是记录下一个节点在数组的哪个位置。),并且使用很少的额外空间,可以说是目前建图和遍历效率最高的存储方式了。
#include<iostream>
#include<cstring>
using namespace std;
#define MAX 100010
#define max(a,b) a>b?a:b
class edges{
public:
int toNode;
int nextEdge;
};
edges edge[2*MAX];
int head[MAX];
int M = 0;//记录边的编号
int dp[MAX][2];
void addEdge(int f,int s){
edge[M].toNode = s;
edge[M].nextEdge = head[f];
head[f] = M++;
edge[M].toNode = f;
edge[M].nextEdge = head[s];
head[s] = M++;
}
void dfs(int node,int pre){
for(int i=head[node];i != -1;i=edge[i].nextEdge){
if(edge[i].toNode == pre) continue;
int n = edge[i].toNode;
dfs(n,node);
dp[node][0] += max(dp[n][1],dp[n][0]);
dp[node][1] += dp[n][0];
}
}
int main(){
int n;
int x,y;
cin>>n;
memset(head,-1,sizeof(head));
memset(dp,0,sizeof(dp));
for(int i=1;i<=n;i++)
cin>>dp[i][1];
for(int i=1;i<n;i++){
cin>>x>>y;
addEdge(x,y);
}
dfs(1,0);
int m = max(dp[1][0],dp[1][1]);
cout<<m<<endl;
return 0;
}
具体的链式前向星的理解我是看的另一位博主的,在此附上原文链接
https://www.cnblogs.com/LQ-double/p/5971323.html