2017多校第10场第8题(树上边匹配)

一开始想到了二分图匹配,找出最大匹配以后如果还有猴子剩下,答案就是匹配数加剩下的猴子数。

后来写完就觉得匈牙利复杂度不够,瞎交了一发 tle了

后来知道了dfs的暴力匹配,创建一个0点,和1 相连,然后跑dfs,见到一条边,两个点都没有被选的话就选。

dfs以后如果0被选了 匹配数就减1,然后算答案

#include<cstdio>
#include<vector>
#include<cstring>
using namespace std;
const int maxn = 100000+10;
int n,k,a;
vector<int>G[maxn];
int vis[maxn];
int in[maxn];
int used[maxn];
int ans ;
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;
void dfs(int u,int fa)
{
    int len = G[u].size();
    for(int i=0;i<len;i++)
    {
        int v = G[u][i];
        dfs(v,u);
    }
    if(!vis[u]&&!vis[fa])
    {
        ans ++; vis[u] = 1; vis[fa] = 1;
    }
}
int main()
{
    int cases;
    read(cases);
    while(cases--)
    {
        read(n); read(k);
        for(int i=0;i<=n;i++) G[i].clear(); ans = 0;
        for(int i=2;i<=n;i++)
        {
            read(a);
            G[a].push_back(i);
        }
        G[0].push_back(1);
        memset(vis,0,sizeof(vis));
        dfs(1,-1);
        if(vis[0]) ans--;
        if(ans*2>=k) printf("%d\n",(k+1)/2);
        else  printf("%d\n",ans+(k-2*ans));
    }
    return 0;
}
//7 7
//1 2 6 6 2 4


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值