HDU 1520 Anniversary party 树状dp
HDU 1520 Anniversary party 树状dp
题意
大体意思说,一个大学要开一个party,大学里会有很多人回去参加,但是并不是很多人都愿意去,因为有可能遇到自己的直接上司。本来是一个放松的场所,遇到自己的直接boss可真的不大放得开,遇到上上级boss还可以,这就给组织这个活动的部门一个难题,每个人都有自己的开心值,我们该怎么做才能既避免这种尴尬,又能使得参加人的开心值总和最大呢?
先给一个n
表示大学里面人的个数,编号从1
开始,然后是n
个值,表示每个人的开心值,接下来是若干个关系,如1 3
表示第三号是第一号的直接boss,当输入0 0
的时候表示结束。
这里是保证关系是一个树,而不会有若干个树。
解题思路
显然这是个求解最优的题目,我们可以使用动态规划来进行解决,因为这个关系是一个树状的,所以也就称为树状dp
了。
这里我们先定义一个状态,dp[i][0]
表示在第i
号员工不参加的情况下,以他为根节点的树的最大值,同样的,dp[i][1]
就表示在第i
号员工参加的情况下,以他为根节点树的最大值。
对于初始化,dp[i][0]=0, dp[i][1]=他参加的开心值
。
递推关系,这里dp[i][1]={dp[son1][0]+dp[son2][0]+... 。son1,son2等表示i的直接孩子编号}
就是一个父节点参加,那么以他为根节点的树的最优值,就是以他的各个孩子节点(不参加时)为根节点树的最优值的和(这里满足最优子结构性质)。
dp[i][0] += max(dp[son][1], dp[son][0]),要对i的每个孩子节点进行判断
。
代码实现
#include<cmath> #include<cstdio> #include<cstring> #include<algorithm> #include<iostream> #include<string> #include<stack> #include<queue> #include<map> #include<set> #include<sstream> typedef long long ll; using namespace std; const double esp=1e-6; const int inf=0x3f3f3f3f; const int MAXN=6e3+7; int fa[MAXN], dp[MAXN][2]; vector<int> tre[MAXN]; bool vis[MAXN]; int n; void dfs(int rt) { for(int i=0; i<tre[rt].size(); i++) dfs(tre[rt][i]); for(int i=0; i<tre[rt].size(); i++) { dp[rt][1] += dp[tre[rt][i]][0]; dp[rt][0] += max(dp[tre[rt][i]][0], dp[tre[rt][i]][1]); } } int main() { while(cin>>n) { for(int i=1; i<=n; i++){ cin>>dp[i][1]; vis[i] = false; fa[i] = i; dp[i][0] = 0; tre[i].clear(); } int a, b; while(cin>>a>>b){ if(a == 0 && b == 0) break; fa[a] = b; tre[b].push_back(a); } int root; for(int i=1; i<=n; i++) if(fa[i] == i){ root = i; break; } dfs(root); cout<<max(dp[root][1], dp[root][0])<<endl; } return 0; }
欢迎评论交流!
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步