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][0∼1] 表示该节点是否与他的父亲节点连接时的最大独立边集,那么我们可以得到转移方程 :
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,那么我们还需多连
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);
}
}