样例树形结构入下:
v代表节点u的子节点
f[u][0]表示不选取节点u对应的最大快乐值,u一旦不选,其孩子就可以选了,f[u][0]+=f[v][1]。
f[u][1]表示选取节点u对应的最大快乐值,u一旦选中,其孩子就不能选了,f[u][1]+=f[v][0]。
样例模拟如下,从叶节点向根节点推进。
f[1][0]=0,f[1][1]=1
f[2][0]=0,f[2][1]=1
f[3][0]=0,f[3][1]=1
f[5][0]=0,f[5][1]=1
f[3][0]+=f[1][1],f[3][0]=1
f[3][0]+=f[2][1],f[3][0]=2
f[3][1]+=f[1][0],f[3][1]=1
f[3][1]+=f[2][0],f[3][1]=1
f[5][0]+=f[3][1],f[5][0]=1
f[5][1]+=f[3][0],f[5][1]=3
f[6][0]=0,f[6][1]=1
f[7][0]=0,f[7][1]=1
f[4][0]=0,f[4][1]=1
f[4][0]+=f[6][1],f[4][0]=1
f[4][0]+=f[7][1],f[4][0]=2
f[4][1]+=f[6][0],f[4][1]=1
f[4][1]+=f[7][0],f[7][0]=1
f[5][0]+=f[4][1],f[5][0]=2
f[5][1]+=f[4][0],f[5][1]=5
max(f[5][0],f[5][1])=5
ybt
未通过
测试点 | 结果 | 内存 | 时间 |
测试点1 | 答案正确 | 624KB | 1MS |
测试点2 | 答案正确 | 620KB | 1MS |
测试点3 | 答案正确 | 632KB | 1MS |
测试点4 | 答案错误 | 628KB | 1MS |
测试点5 | 答案正确 | 636KB | 1MS |
测试点6 | 答案正确 | 644KB | 1MS |
测试点7 | 答案正确 | 652KB | 1MS |
测试点8 | 答案正确 | 972KB | 2MS |
测试点9 | 答案正确 | 964KB | 2MS |
测试点10 | 答案正确 | 972KB | 2MS |
测试点11 | 答案正确 | 1284KB | 3MS |
LOJ
LUOGU
样例通过,90分代码如下:
#include <bits/stdc++.h>
#define maxn 6010
using namespace std;
struct node{
int to,next;
}e[maxn<<1];
int f[maxn][2];
int head[maxn],tot,n,father[maxn],root;
void add(int u,int v){
tot++,e[tot].to=v,e[tot].next=head[u],head[u]=tot;
}
void init(){
int i,u,v;
scanf("%d",&n);
for(i=1;i<=n;i++)scanf("%d",&f[i][1]);
for(i=1;i<n;i++){
scanf("%d%d",&v,&u);
father[v]=u;
add(u,v),add(v,u);
}
for(i=1;i<=n;i++)
if(!father[i])root=i;//找根节点,根节点无父亲
}
void dfs(int u,int fa){
int i,v;
for(i=head[u];i;i=e[i].next){
v=e[i].to;
if(v==fa)continue;
dfs(v,u);
f[u][0]+=f[v][1];
f[u][1]+=f[v][0];
}
}
int main(){
init();
dfs(root,-1);
printf("%d\n",max(f[root][0],f[root][1]));
return 0;
}
看了出错的数据点:
输入:
7
1
1
1
1
-128
1
1
1 3
2 3
6 4
7 4
4 5
3 5
0 0
输出:
4
上述代码的输出:
2
想了想,状态转移方程,需改进。
v代表节点u的子节点
f[u][0]表示不选取节点u对应的最大快乐值,u一旦不选,其孩子就可以选了,也可以不选,
f[u][0]+=max(f[v][1],f[v][0])。
f[u][1]表示选取节点u对应的最大快乐值,u一旦选中,其孩子就一定不能选了,f[u][1]+=f[v][0]。
经修改,上述例子很快通过。
ybt
通过
测试点 | 结果 | 内存 | 时间 |
测试点1 | 答案正确 | 632KB | 1MS |
测试点2 | 答案正确 | 620KB | 2MS |
测试点3 | 答案正确 | 624KB | 2MS |
测试点4 | 答案正确 | 620KB | 2MS |
测试点5 | 答案正确 | 628KB | 2MS |
测试点6 | 答案正确 | 640KB | 2MS |
测试点7 | 答案正确 | 640KB | 2MS |
测试点8 | 答案正确 | 964KB | 3MS |
测试点9 | 答案正确 | 960KB | 3MS |
测试点10 | 答案正确 | 960KB | 3MS |
测试点11 | 答案正确 | 1296KB | 4MS |
LOJ
LUOGU
AC代码如下:
#include <bits/stdc++.h>
#define maxn 6010
using namespace std;
struct node{
int to,next;
}e[maxn<<1];
int f[maxn][2];
int head[maxn],tot,n,father[maxn],root;
void add(int u,int v){
tot++,e[tot].to=v,e[tot].next=head[u],head[u]=tot;
}
void init(){
int i,u,v;
scanf("%d",&n);
for(i=1;i<=n;i++)scanf("%d",&f[i][1]);
for(i=1;i<n;i++){
scanf("%d%d",&v,&u);
father[v]=u;
add(u,v),add(v,u);
}
for(i=1;i<=n;i++)
if(!father[i])root=i;//找根节点,根节点无父亲
}
void dfs(int u,int fa){
int i,v;
for(i=head[u];i;i=e[i].next){
v=e[i].to;
if(v==fa)continue;
dfs(v,u);
f[u][0]+=max(f[v][1],f[v][0]);
f[u][1]+=f[v][0];
}
}
int main(){
init();
dfs(root,-1);
printf("%d\n",max(f[root][0],f[root][1]));
return 0;
}
该题习得什么:
节点选还是不选,对应子节点选还是不选,理解更深了。