题意:给定一棵树,要使至少两只猴子连在一起(没有一个被孤立),最少保留几条边。猴子可以随意放在哪个点,一个点最多一个。
思路:在树中找,两个点,一条边的情况,最多有几条(最大匹配)。这样边最少。猴子不够放的话,每多一只,多放一条边。对于一个点,只要它的儿子中有一个点没有匹配,它就和那个点,组成一对。
PS:还卡读入,算是学到了。留个模板
#include<bits/stdc++.h>
using namespace std;
namespace fastIO
{
#define BUF_SIZE 100000
//fread -> read
bool IOerror = 0;
inline char nc() {
static char buf[BUF_SIZE], *p1 = buf + BUF_SIZE, *pend = buf + BUF_SIZE;
if(p1 == pend) {
p1 = buf;
pend = buf + fread(buf, 1, BUF_SIZE, stdin);
if(pend == p1) {
IOerror = 1;
return -1;
}
}
return *p1++;
}
inline bool blank(char ch) {
return ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t';
}
inline void read(int &x) {
char ch;
while(blank(ch = nc()));
if(IOerror)
return;
for(x = ch - '0'; (ch = nc()) >= '0' && ch <= '9'; x = x * 10 + ch - '0');
}
#undef BUF_SIZE
};
using namespace fastIO;
const int MAX=1e6;
struct Edge
{
int to,next;
}edge[MAX];
int head[MAX],tot;
int vis[MAX],ans;
int dfs(int k)
{
vis[k] = 1;
int num = 0,pei = 0;
for(int i = head[k]; i != -1; i = edge[i].next)
{
int y = edge[i].to;
if(vis[y]) continue;
num++;
pei += dfs(y);
}
if(num - pei >= 1)
{
ans++;
return 1;
}
else
return 0;
}
void init()
{
memset(head,-1,sizeof head);
tot = 0;
memset(vis,0,sizeof vis);
ans = 0;
}
void add(int a,int b)
{
edge[tot].to = b;
edge[tot].next = head[a];
head[a] = tot++;
}
int main()
{
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
int T,n,monkey;
read(T);
while(T--)
{
read(n);read(monkey);
init();
for(int i=1,x;i<n;i++)
{
read(x);
add(x,i+1);
add(i+1,x);
}
dfs(1);
if(2*ans >= monkey)
printf("%d\n",monkey/2 + monkey%2);
else
printf("%d\n",ans + monkey - 2*ans);
}
return 0;
}