HDU 6178 Monkeys(贪心+dfs)

探讨了如何在给定的树形结构中通过贪心策略寻找最大匹配数,以解决特定条件下边的最少数目的问题。输入包含多个测试用例,每个用例给出一棵树的节点数量及树的结构,输出则是满足条件的最少边数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Description

给一棵nn个节点的树,要求删去最多的边,使得剩下的边可以满足,从n个点中选出kk个点,k个点中的每一个点都可以通过剩下的边至少与这kk个点中的另一个点相连,问剩下的最少边数

Input

第一行一整数T表示用例组数,每组用例首先输入两个整数nnk,之后输入n1n−1个正整数a1,...,an1a1,...,an−1aiaii+1i+1相连表示一条树边(1T100,2kn100000)(1≤T≤100,2≤k≤n≤100000)

Output

对于每组用例,输出剩下的最少边数

Sample Input

2
4 4
1 2 3
4 3
1 1 1

Sample Output

2
2

Solution

贪心,最优是一条边连两个且边互不相交,从树叶开始dfsdfs,找出树的最大匹配数numnum,即这棵树最多可以找到numnum条边不相交,注意到这numnum条最多我们选k2⌊k2⌋条,故取ans=min(num,k2)ans=min(num,⌊k2⌋)表示至多有ansans条边可以互不相交且每条边连kk个点中的两个,这样剩下的k2ans个点就只能每个点连一条边到这ansans条边上,答案为kansk−ans

Code

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
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;
#define maxn 100001
struct node
{
    int v,next;
}edge[2*maxn];
int tot,head[maxn];
int T,n,k,num;
void init()
{
    tot=0;
    memset(head,-1,sizeof(head));
}
void add(int u,int v)
{
    edge[tot].v=v,edge[tot].next=head[u],head[u]=tot++;
}
int dfs(int u,int fa)
{
    int cnt=0;
    for(int i=head[u];~i;i=edge[i].next)
    {
        int v=edge[i].v;
        if(v==fa)continue;
        cnt+=dfs(v,u);
    }
    if(cnt)
    {
        num++;
        return 0;
    }
    return 1;
}
int main()
{
    read(T);//scanf("%d",&T);
    while(T--)
    {
        read(n);read(k);//scanf("%d%d",&n,&k);
        init();
        for(int i=2;i<=n;i++)
        {
            int a;
            read(a);//scanf("%d",&a);
            add(a,i),add(i,a);
        }
        num=0;
        dfs(1,1);
        num=min(num,k/2);
        printf("%d\n",k-num);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值