题意:
给你一颗树,删除最多的边,使得k个猴子能落在n个结点上(每个猴子所在的节点周围至少连着一个有猴子的节点)
思路:
要使得剩下的边最少,那么两个点只配一条边是最优的,计算出这种边的最大条数,如果这些边不够连接k个猴子,那么每剩下一个猴子就要多加一条边。
所以只要从度数为1的节点开始找,bfs一下就好。
多校的时候认为这个思路没错,不管怎么优化就是疯狂tle,换了一个快的但是不一定对的思路,还是t,t到怀疑人生啊。后来结束了才知道有输入挂这种东西,。。。之前用cin的时候T过,就老老实实的用scanf,,以为scanf已经是最快了,,没想到还有fread这种快速读文件的东西。。
代码:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5+7;
vector<int> arr[maxn];
int pd[maxn],vis[maxn];
struct FastIO
{
static const int S = 2*100;
int wpos;
char wbuf[S];
FastIO() : wpos(0) {}
inline int xchar()
{
static char buf[S];
static int len = 0, pos = 0;
if (pos==len)
pos = 0, len = fread(buf, 1, S, stdin);
if (pos==len) exit(0);
return buf[pos ++];
}
inline int xint()
{
int s = 1, c = xchar(), x = 0;
while(c<=32) c = xchar();
if(c=='-') s = -1, c = xchar();
for(;'0'<=c && c<='9';c=xchar()) x = x*10+c-'0';
return x * s;
}
~FastIO()
{
if(wpos) fwrite(wbuf, 1, wpos, stdout), wpos = 0;
}
}io;
int main()
{
int t;
scanf("%d",&t);
memset(pd,0,sizeof(pd));
while(t--)
{
int n,k;
n = io.xint();
k = io.xint();
memset(vis,0,sizeof(vis));
for(int i = 1;i<=n;i++)
arr[i].clear();
for(int i = 2;i<=n;i++)
{
int a;
a = io.xint();
arr[a].push_back(i);
arr[i].push_back(a);
pd[a]++;
pd[i]++;
}
queue<int> q;
for(int i = 1;i<=n;i++)
{
if(pd[i]==1)
q.push(i);
pd[i] = 0;
}
int ans = 0;
while(!q.empty())
{
int now = q.front();
q.pop();
if(arr[now].size()!=0)
{
int v = arr[now][0];
if(vis[now]==0&&vis[v]==0)
{
ans++;
vis[now] = 1;
vis[v] = 1;
}
arr[v].erase(remove(arr[v].begin(),arr[v].end(),now),arr[v].end());
if(arr[v].size()==1)
q.push(v);
}
}
if(ans*2>=k)
{
printf("%d\n",(k+1)/2);
}
else
{
printf("%d\n",ans+k-ans*2);
}
}
return 0;
}