小Hi在Hihoole公司的实习期结束了。在回学校前,他决定请部门所有同事来住所聚会。
已知小Hi一共有N名同事,编号1~N,其中第i名同事的酒量是Ai。
这N名同事的上下级关系恰好组成一棵树型结构。对于第i名同事来说,如果他的直接上级没有出席聚会,他会喝掉Ai单位的酒;如果他的直接上级出席了聚会,他会有所收敛,只喝掉Ai/2单位的酒。
小Hi想知道,自己至少要准备多少单位的酒,才能保证无论哪些人出席聚会,酒都够喝。
Input
第一行包含一个整数N。(1 <= N <= 100000)
第二行包含N个整数,A1, A2, ... AN。(0 <= Ai <= 100000)
以下N-1行每行包含两个整数u和v,代表u是v的直接上级。
Output
小Hi至少需要准备的酒量,保留1位小数。
Sample Input
5
5 2 4 1 4
2 4
2 1
1 5
1 3
Sample Output
10.5
第一次做树形DP,寻找父亲节点和子节点的关系,DFS整颗树,进行DP;
ps:先寻找根节点ROOT 从ROOT处一直DFS到叶子节点,自底向上,寻找关系,最后到f[root];
这是最简单的树形DP,比水题还简单,好像,我还没真正体会到真谛。
#include <iostream>
#include <vector>
#include <string>
#include <bits/stdc++.h>
using namespace std;
int a[100005];
int degree[100005];
double f[100005][2]; //0代表不取,1代表取
vector<int> gr[100005];
void dfs(int u) //搜索
{
int len=gr[u].size();
f[u][1]=a[u]*1.0;
for(int i=0;i<len;i++)
{
dfs(gr[u][i]);
f[u][0]+=max(f[gr[u][i]][0],f[gr[u][i]][1]);
f[u][1]+=max(f[gr[u][i]][1]-a[gr[u][i]]*0.5,f[gr[u][i]][0]);
}
}
int main()
{
cin.tie(0);
memset(f,0,sizeof(0));
int n;
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>a[i];
//degree[i]=-1;
}
for(int i=1;i<n;i++)//记录入度和子节点
{
int x,y;
cin>>x>>y;
gr[x].push_back(y);
degree[y]++;
}
int root;
for(int i=1;i<=n;i++)
if(degree[i]==0)//寻找根
{
root=i;
dfs(root);
//break;
}
printf("%.1f\n",max(f[root][0],f[root][1]));
return 0;
// cout<<max(f[root][0],f[root][1])<<endl;
}