删除一个节点和它儿子之间的所有边,实际产生了它的出度数+1个联通块
所以求是否能产生k个联通块,就是将所有出度数统计到一个数组中,查找数组中是否能找到某些数相加等于k,实际就是01背包
当然整个树就是一个联通块
#include<iostream>
using namespace std;
const int N=3005;
int n,tree[N],dp[N*N];
int main()
{
cin>>n;
int x;
for(int i=1;i<n;i++)
{
cin>>x;
tree[x]++;
}
dp[0]=1;
for(int i=1;i<=n;i++)
{
for(int j=n-1;j>=tree[i];j--)
{
if(dp[j-tree[i]]!=0)
{
if(j-tree[i]==0) dp[j]=1;
else
{
if(dp[j]==0) dp[j]=dp[j-tree[i]]+1;
else dp[j]=min(dp[j],dp[j-tree[i]]+1);
}
}
}
}
cout<<"0";
for(int i=1;i<n;i++)
{
cout<<" ";
if(dp[i]==0) cout<<"-1";
else cout<<dp[i];
}
}