最大的独立集:任意选择一些点使得任意两个点之间没有连接
所以可以得到以下两个条件:1.父亲和儿子不能连接在一起
2.因为如果选择了父亲就不能选择儿子和爷爷节点所以如果选择父亲的话爷爷的最大值就是父亲的最大值,由1得到爷爷的最大值为所有儿子的和或者所有孙子的和加上自己。
其中d为最大值,s为节点i的所有儿子的编号,gs为所有i的孙子节点
得到以下的dp函数
1
2
3
4
5
6
7
8
9
10
void dp(int u, int fa){
int d = G[u].size();
for(int i=1;i<=d;i++){
int v = G[u][i];
if(v != fa) dp(v,u);
gs[fa] += f[v];
s[u] += f[v];
}
f[u] = max(s[u],gs[u]+save[u]);
}
可以用来解决如下的问题:
问题 没有上司的晚会
题目描述
Ural大学有N个职员,编号为1~N。他们有从属关系,也就是说他们的关系就像一棵以校长为根的树,父结点就是子结点的直接上司。每个职员有一个快乐指数。现在有个周年庆宴会,要求与会职员的快乐指数最大。但是,没有职员愿和直接上司一起参加宴会。
输入
第一行一个整数N。(1≤N≤6000)
接下来N行,第i+1行表示i号职员的快乐指数Ri。(-128≤Ri≤127)
接下来N-1行,每行输入一对整数L,K。表示K是L的直接上司。
最后一行输入0,0。
输出
第1行:输出最大的快乐指数。
样例输入
7
1
1
1
1
1
1
1
1 3
2 3
6 4
7 4
4 5
3 5
0 0
样例输出
5
下面附上代码:
#include<cstdio>
#include<vector>
#define MAXN 6000
using namespace std;
vector <int> G[MAXN+10];
int f[MAXN+10], s[MAXN+10], gs[MAXN+10];
int father[MAXN+10],save[MAXN+10];
int n;
void read()
{
int i, u, v;
scanf("%d", &n);
for(i=1;i<=n;i++){
scanf("%d",&u);
save[i] = u;
}
while(true) {
scanf("%d%d", &u, &v);
if(u == v&& u == 0)
break;
G[u].push_back(v);
G[v].push_back(u);
}
}
void dfs(int u, int fa)
{
father[u] = fa;
int d = G[u].size();
int v;
for(int i = 0; i < d; i++) {
v = G[u][i];
if(v != fa)
dfs(v, u);
}
}
void dp(int u, int fa)
{
int d = G[u].size();
int v;
for(int i = 0; i < d; i++) {
v = G[u][i];
if(v != fa) {
dp(v, u);
s[u] += f[v];
if(father[u])
gs[father[u]] += f[v];
}
}
f[u] = max(s[u], gs[u]+save[u]);
}
int main()
{
read();
dfs(1, 0);
dp(1, 0);
printf("%d\n", f[1]);
return 0;
}