[NOIP模拟] 拆网线 树形DP

来源:互联网 发布:another mysql daemon 编辑:程序博客网 时间:2024/05/21 22:42

Description

    给出一棵树,现去掉一些边,使树存在 K 个点,每点至少与其中一个点相连,求最小**边。

Input

    t 组数据,n 个点的树,K,以及相连的边。

Output

    答案。

Sample input

2
4 4
1 2 3
4 3
1 1 1

Sample output

2
2



Solution :

     我们定 DP[i][01] 表示该节点是否与他的父亲节点连接时的最大独立边集,那么我们可以得到转移方程 :

DP[i][0]=DP[j][0]+max(max(DP[j][1]DP[j][0]),0)
DP[i][1]=DP[j][0]

    那么这棵树的最大独立边集就为 DP[1][0], 如果 K 大于最大边集 * 2,那么我们还需多连 KDP[1][0]2 的边,如果小于那我们需要连 K/2+(Kand1) 边。


Code :

#include <cstdio>#include <cstdlib>#include <cstring>#include <string>#include <algorithm>#include <iostream>#include <cmath>#include <ctime>#include <map>#include <vector>using namespace std;inline int read() {    int i = 0, f = 1;    char ch = getchar();    while(!isdigit(ch)) {        if(ch == '-') f = -1; ch = getchar();    }    while(isdigit(ch)) {        i = (i << 3) + (i << 1) + ch - '0'; ch = getchar();    }    return i * f;}const int MAXN = 1e5 + 5;int dp[MAXN][2], first[MAXN], nxt[MAXN * 2], to[MAXN * 2], n, k, tot;inline void addedge(int x, int y) {    nxt[++tot] = first[x]; first[x] = tot; to[tot] = y;    nxt[++tot] = first[y]; first[y] = tot; to[tot] = x;}inline void dfs(int x, int fa) {    dp[x][1] = 1; dp[x][0] = 0;    int mx = 0;    for(int i = first[x]; i; i = nxt[i]) {        if(to[i] != fa) {            dfs(to[i], x);            dp[x][1] += dp[to[i]][0];            dp[x][0] += dp[to[i]][0];            mx = max(dp[to[i]][1] - dp[to[i]][0], mx);        }    }    dp[x][0] += mx;}int main() {    int t = read();    while(t--) {        memset(first, 0, sizeof(first));        memset(nxt, 0, sizeof(nxt));        tot = 0;        n = read(), k = read();        for(int i = 1; i <= n - 1; ++i) addedge(read(), i + 1);        dfs(1, 1);         int now = dp[1][0];        if(now * 2 >= k) printf("%d\n", k / 2 + (k & 1));        else printf("%d\n", now + k - now * 2);     }}
原创粉丝点击