hihocoder 1453 Rikka with Tree (简单DP)

网友投稿 264 2022-08-30

hihocoder 1453 Rikka with Tree (简单DP)

描述

众所周知,萌萌哒六花不擅长数学,所以勇太给了她一些数学问题做练习,其中有一道是这样的:勇太有一棵 n 个节点的以1为根的有根树。现在他可以对这棵树进行若干次操作,每一次操作可以选择树上的一个点然后删掉这个点和它的儿子之间的所有边。现在勇太想要知道对于每一个 k ∈ [1, n],最少需要多少次操作才能让图中恰好存在 k 个联通块。当然,这个问题对于萌萌哒六花来说实在是太难了,你可以帮帮她吗?

输入

第一行输入一个正整数 n (n ≤ 3000)。第二行输入 n-1 个整数 fi 表示 i+1 号点的父亲,保证 1 ≤ fi ≤ i。

输出

输出 n 个整数,第 i 个数表示 k=i 时的答案,如果无法让图中恰好存在 k 个联通块,则输出-1。

样例输入

61 2 1 1 2

样例输出

0 -1 1 1 -1 2

思路:

因为题目中有说明,第二行输入 n−1 个整数 fi 表示 i+1,因此,我们建的图刚开始一定是一个连通图,所以输出的时候第一个答案一定是0咯!

照着样例画出图,我们可以发现,它本身是一个连通块,而当我们想要将它拆分成两个连通块,需要切除一个出度为1的点,若图中不存在这样的点,则输出-1;想要将图拆分成六个连通块,需要减少五个出度,也就是找最少有几个点的出度和为5,输出的是点的个数。

发现规律之后我们可以建图,采用邻接表存储,每个点的出度即为它所邻接点的个数。

然后在这些数中寻找最小能通过加法组合成 k−1

AC代码:

#include #include #include #include#includeusing namespace std;vectorG[3005];int dp[1000000]; //dp[i] 代表组合成i所需要的最少数的个数int weight[3005],sum;void init(int n){ dp[0]=1; for(int i=1; i<=n; i++) for(int z=sum; z>=weight[i]; z--) if(dp[z-weight[i]]) //找到一个组合 { if(z-weight[i]==0)dp[z]=1; //如果该点是独立组合出所需要的值 else { if(dp[z]==0)dp[z]=dp[z-weight[i]]+1; //如果当前位置原来没有被计算过 else dp[z]=min(dp[z],dp[z-weight[i]]+1); //对已经计算过的位置取最小值 } }}int main(){ int N,par; scanf("%d",&N); for(int i=1; i

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:爱奇艺奇麟新娱乐营销“三板斧”,将如何改变营销行业?(爱奇艺产品策略)
下一篇:用博弈的思想看世界
相关文章

 发表评论

暂时没有评论,来抢沙发吧~