深搜。。。
题意:
有一棵有n个节点的树,现在要去掉多余的边,但是要保证k个特殊节点至少两两连接,问最后可以剩下多少条边。
思路:
为了保证特殊的节点,最完美的状态时k条边都两两连接,那么会使用k/2条边,(奇数的情况需要加1)。当然如果树中没有那么多的两两连接的边,就会要多用一些边,也就是剩下多少特殊边就要用多少边。所以问题就是找到这样的两两边有多少。为了找出最多的两两边,要从儿子回溯,很明显dfs可以做到。最开始我用queue维护入度为1的边,每次删除两两的边从叶子节点开始删,但是傻了用了vector和queue,用深搜多美好呀!
- 注意要用超级输入,借用大佬的代码。
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int maxn = 100005;
struct Node
{
int to,next;
}node[maxn*2];
int head[maxn];
int n,k;
int dp[maxn],lone;
namespace fastIO {
#define BUF_SIZE 1000000
//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;
void dfs(int u,int fa)
{
for(int i = head[u];i != -1; i = node[i].next) {
int to = node[i].to;
if(to == fa) continue;
dfs(to,u);
if(!dp[to]) {
if(!dp[u]) {
dp[to] = dp[u] = true;
}
else lone++;
}
}
}
int main()
{
//freopen("in.txt","r",stdin);
int tt;
//scanf("%d",&tt);
read(tt);
while(tt--) {
//scanf("%d%d",&n,&k);
read(n);
read(k);
memset(head,-1,sizeof(head));
int pos = 1;
for(int i = 2;i <= n; i++) {
int temp;
//scanf("%d",&temp);
read(temp);
node[pos].to = temp;
node[pos].next = head[i];
head[i] = pos++;
node[pos].to = i;
node[pos].next = head[temp];
head[temp] = pos++;
}
memset(dp,0,sizeof(dp));
lone = 0;
dfs(1,0);
lone += (dp[1]?0:1);
int num = (n-lone)/2 ;
int ans;
if(num*2 >= k) {
ans = k/2 + (k%2 == 1 ? 1:0);
}
else {
ans = num + k-num*2;
}
printf("%d\n",ans);
}
return 0;
}