求用最小数量的边使得树上至少k个点被这些边覆盖
2≤k≤n≤105
显然,一条边覆盖两个点最好。
考虑最多能有多少边能覆盖两个点,用树形dp即可
复杂度O(n)
#include<bits/stdc++.h>
#define LEN
using namespace std;
inline int getint(){
int x=0,p=1;
char c=getchar();
while(!isdigit(c)){
if(c=='-')p=-1;
c=getchar();
}
while(isdigit(c)){
x=(x<<3)+(x<<1)+(c^'0');
c=getchar();
}
return x*p;
}
int dp[100005][2];
struct tree{
int fa;
vector<int>son;
}t[100005];
void dfs(int cur){
dp[cur][1]=dp[cur][0]=0;
for(int i=0;i<t[cur].son.size();++i){
int v=t[cur].son[i];
dfs(v);
dp[cur][0]+=max(dp[v][1],dp[v][0]);
}
for(int i=0;i<t[cur].son.size();++i){
int v=t[cur].son[i],x;
if((x=dp[cur][0]-max(dp[v][0],dp[v][1])+dp[v][0]+1)>dp[cur][1]){
dp[cur][1]=x;
}
}
}
int main(){
int T=getint();
while(T--){
memset(dp,0,sizeof(dp));
memset(t,0,sizeof(t));
int n=getint(),k=getint();
for(int i=2;i<=n;++i){
int fa=getint();
t[fa].son.push_back(i);
t[i].fa=fa;
}
dfs(1);
int ans=max(dp[1][0],dp[1][1]);
//cout<<ans<<endl;
if(k<=ans*2){
cout<<(k+1)/2<<endl;
}
else{
cout<<ans+k-ans*2<<endl;
}
}
return 0;
}
本文介绍了一种使用树形动态规划算法解决特定问题的方法:即如何利用最少数量的边来确保树上的至少k个节点被覆盖。该算法通过递归地分析每个节点的最佳覆盖方案,最终得出整个树的最优解。
207

被折叠的 条评论
为什么被折叠?



