首页 >> 大全

2022-05-07每日刷题打卡

2023-08-17 大全 28 作者:考证青年

有一棵 n 个节点的以1为根的有根树。现在可以对这棵树进行若干次操作,每一次操作可以选择树上的一个点然后删掉这个点和它的儿子之间的所有边。

现在想要知道对于每一个 k∈[1,n],最少需要多少次操作才能让图中恰好存在 k 个联通块。

输入格式

第一行输入一个正整数 n。

第二行输入 n−1 个整数 fi 表示 i+1 号点的父亲,保证 1≤fi≤i。

输出格式

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

每日一刷_每日刷题app_

样例输入1

6
1 2 1 1 2

样例输出1

0 -1 1 1 -1 2

数据规模

共10个测试点。

测试点1,2,3满足n≤20。

每日一刷_每日刷题app_

测试点4,5,6满足n≤100。

对于所有数据,满足1≤n≤3000。

问题解析

这题其实就是背包问题的转化。

因为我们是每次选一个点,把它和它孩子的所有点的链接都断开,拿样例来说,连在第一个点上的点有三个,那么我们要是选择了第一个点,那么第一个点和它三个孩子的链接就会断开,这样此时就会有4个连通块:第一个点+第一个点的三个孩子。连在第二个点上的孩子有两个,所以我们要是断开第二个点,那么连通块就会有三个,如果把1和2都选了,那么一共就是6个连通块(样例如图所示)。

那么此时就相当于一个背包问题了,我们转化一下:每个点有多少孩子,相当于这个货物值多少钱。比如第一个点,有3个孩子,所以它的价值是3,当我们选择拿这个点放入背包,那么我们的价值就+3,即多了三个连通块。然后我们就根据需要的总价值(总连通块数)来选择我们需要的货物即可。

#include
using namespace std;
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include#define endl '\n';
typedef long long ll;
typedef pairPII;
const int MOD = 1e9 + 7, N = 3010;int n, f[N], w[N];int main()
{cin >> n;for (int i = 2; i <= n; i++){int x;cin >> x;w[x]++;}memset(f, 0x3f, sizeof f);f[1] = 0;for (int i = 1; i <= n; i++){if (w[i] == 0)continue;for (int j = n; j >= w[i]; j--)f[j] = min(f[j], f[j - w[i]] + 1);}for (int i = 1; i <= n; i++){if (f[i] == 0x3f3f3f3f)cout << -1 << " ";else cout << f[i] << " ";}return 0;
}

关于我们

最火推荐

小编推荐

联系我们


版权声明:本站内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 88@qq.com 举报,一经查实,本站将立刻删除。备案号:桂ICP备2021009421号
Powered By Z-BlogPHP.
复制成功
微信号:
我知道了