习题:Beavermuncher-0xFF(树DP)
题目
思路
算是比较明显的一个树DP
设\(dp_i\)表示遍历以i为根节点的子树能吃的最多的海狸
合并儿子节点的DP值只需要累加就可以了
注意可能有根节点海狸不够的情况,所以我们还要把儿子节点的DP值排个序
但是注意,这里并不保证i号节点的海狸被吃完了,所以转移的时候我们需要将这个因素考虑进去
我们只需要统计一下,再更新即可
代码
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
int n,s;
int val[100005];
long long dp[100005],ans;
vector<int> g[100005];
/*
以i为根节点的子树,从i出发回到i,根节点至少剩余1只海狸的方案数
*/
bool cmp(const int &a,const int &b)
{
return dp[a]>dp[b];
}
void dfs(int u,int fa)
{
if(g[u].size()==1&&g[u].front()==fa)
return;
long long t;
if(u==s)
t=val[u];
else
t=val[u]-1;
long long s=0;
for(int i=0;i<g[u].size();i++)
{
int v=g[u][i];
if(v!=fa)
{
dfs(v,u);
}
}
sort(g[u].begin(),g[u].end(),cmp);
for(int i=0;i<g[u].size();i++)
{
int v=g[u][i];
if(v!=fa)
{
if(t==0)
break;
dp[u]+=dp[v];
if(dp[v])
{
t--;
dp[u]+=2;
s+=val[v]-1;
}
else
s+=val[v];
}
}
dp[u]=dp[u]+2*min(t,s);
val[u]=t-min(t,s)+1;
}
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
cin>>val[i];
for(int i=1,u,v;i<n;i++)
{
cin>>u>>v;
g[u].push_back(v);
g[v].push_back(u);
}
cin>>s;
dfs(s,-1);
cout<<dp[s];
return 0;
}

浙公网安备 33010602011771号