没有上司的舞会 题解

没有上司的舞会
时间限制:0秒 内存限制:128M
题目描述
Ural大学有N个职员,编号为1~N。他们有从属关系,也就是说他们的关系就像一棵以校长为根的树,父结点就是子结点的直接上司。每个职员有一个快乐指数。现在有个周年庆宴会,要求与会职员的快乐指数最大。但是,没有职员愿和直接上司一起与会。
输入描述
第一行一个整数N。(1< =N< =6000)
接下来N行,第i+1行表示i号职员的快乐指数Ri。(-128< =Ri< =127)
接下来N-1行,每行输入一对整数L,K。表示K是L的直接上司。
最后一行输入0,0。
输出描述
输出最大的快乐指数。
样例
输入
7
1
1
1
1
1
1
1
1 3
2 3
6 4
7 4
4 5
3 5
0 0
输出
5
今天为大家带来一道树形dp题----------没有上司的舞会的题解,其实此题有两种思路:1.利用邻接表存储树的信息,从而找出树根及树根的孩子,最后直接查邻接表从而求出其快乐最大值。2.普通思路,利用二重循环填二维数组,最后查表得出结论。小编推荐邻接表的方法,毕竟填完邻接表直接查的速度普遍比二重循环查表更快。在此也为大家规避掉一个错误的方法,也许有一些朋友想利用邻接矩阵来实现存储树的信息再查表。虽然速度也很快,但请看:内存限制:128M,oAo。爆内存啊。邻接矩阵所浪费的空间太多导致内存超限。
其实此题十分基础,也没什么可讲的,具体要注意的看一下小编的注释吧,现在为大家献上第二种思路的AC代码。
tips:其实小编在写这道题时遇到了一个问题,找了很久才找出来错误。以后因此为戒养成一个好习惯, 尽量不要让自定义函数(有时main也不行)中的变量与全局变量重名有时递归或递推时会出现一些意想不到的问题,例如本题中小编写的c数组,当它为放在main函数外面作为全局变量出现时,c存储的会变成变量存储其子节点的子节点……一直下去直到其子孙节点中的叶子结点停下,存储的值错误,输出2这个错误结果。也请大家引以为戒,定义变量时除非万不得已(例如主函数内的空间存不下数组时),尽量不要将其定义为全局变量,哪来的就定义在哪,避免发生一些不好的事情。

#include<iostream>
using namespace std;
const int N=6060;
int f[N][3],a[6001],b[6001]={0}; //f数组负责存储职员的快乐最大值,而a数组负责存储每位员工的快乐值,b数组利用存储每个节点的父亲节点从而找出树根并将其值赋入root变量。也可逆用找出父节点的子节点。
int n;
void dfs(int root)
{
int c[6001]={0};//c数组存储父节点的子节点
int i,t=0;
for(i=1;i<=n;i++)
{
if(b[i]==root)
{
t++;
c[t]=i;
}//利用t来控制c数组的存储空间,并将遍历出的此父节点的子节点t存入c数组
}
if(t==0)//t也可用于判断此节点是否为叶子结点,如果是,则返回上一次递归
{
f[root][1]=a[root];
f[root][0]=0;
return ;//返回上一次递归
}
f[root][1]=a[root];
for(i=1;i<=t;i++)//遍历此父节点的子节点
dfs(c[i]);//递归搜索此父节点的子节点并执行操作
f[root][0]+=max(f[c[i]][0],f[c[i]][1]);//将最大快乐值存入
f[root][1]+=f[c[i]][0];
}
}//dfs搜索函数,递归搜索所有节点
int main()
{
int t,t1,root;
int i;
cin>>n;
for(i=1;i<=n;i++)
{
cin>>a[i];
}//输入员工快乐值
for(i=1;i<=n;i++)
{
cin>>t>>t1;
b[t]=t1;
}//在b数组中录入树的信息将并将以子节点的单元录入其父节点的数值
for(i=1;i<=n;i++)
{
if(b[i]==0)//如果一个节点的值没有被更改为其父节点的信息而仍保持初始值0,代表其没有父节点,即此节点为根节点
{
root=i;//将遍历到的根节点i,存入root变量
dfs(root);//递归搜索子节点从根节点开始
}
}
cout<<max(f[root][0],f[root][1])<<endl;//输出f[root][0]与f[root][1]之间的最大值输出,即职员的最大快乐值,即正解
return 0;//完美结束
}

原文地址:https://www.cnblogs.com/tcwbob/p/13417036.html