hdu 6178 Monkeys

30 篇文章 1 订阅
6 篇文章 0 订阅

Problem

acm.hdu.edu.cn/showproblem.php?pid=6178

Meaning

要在一棵 n 个点的树上放 k 只猴子,然后删掉尽量多的边,使得删边后,每只猴子都至少和另外一只猴子相连,问最后剩下的边数。

Analysis

因为至少两只猴子相连,就贪心地把树拆成“点 - 边 - 点”这样的片段,成对地放猴子,如果还不够放,剩下的结点都是孤立的,要补边连上任意一对,每补一只猴子就加一条边。可以一次简单地深搜贪心拆树,或者一次简单的树型 DP。

  • 这题的考点主要是读入外挂。模板来自这次多校第一场的最后一题的标程。(看这程序好像是只能读非负整数)
  • 这个读入挂想在本地测试的时候,要用freopen()来输入重定向,直接用stdin键盘输入是行的;但交题的时候不用加重定向(除非题目说明)

Code

#include <cstdio>
#include <cstring>
using namespace std;

/*------- 开挂 -------*/
namespace fastIO {
    #define BUF_SIZE 100000
    // fread -> read
    bool IOerror = 0;

    char nc() {
        static char buf[BUF_SIZE], *pl = buf + BUF_SIZE, *pr = buf + BUF_SIZE;
        if(pl == pr) {
            pl = buf;
            pr = buf + fread(buf, 1, BUF_SIZE, stdin);
            if(pr == pl) {
                IOerror = 1;
                return -1;
            }
        }
        return *pl++;
    }

    inline bool blank(char ch) {
        return ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t';
    }

    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 N = 100000;

int head[N+1], to[N<<1], nxt[N<<1];

void add_edge(int f, int t, int sz)
{
    to[sz] = t;
    nxt[sz] = head[f];
    head[f] = sz;
}

bool paired[N+1];
int odd; // 落单的点数

void dfs(int v, int f)
{
    for(int i = head[v]; ~i; i = nxt[i])
        if(to[i] != f)
        {
            dfs(to[i], v);
            if(!paired[to[i]]) // 子结点未被配对
            {
                if(paired[v]) // 当前结点已配对, 不能跟它配
                    ++odd; // 子结点落单
                else // 当前结点跟它配对
                    paired[v] = paired[to[i]] = true;
            }
        }
}

int main()
{
    int T;
    read(T);
    for(int n, k, ans; T--; )
    {
        read(n);
        read(k);
        memset(head, -1, sizeof head);
        for(int f = 2, t, sz = 0; f <= n; ++f)
        {
            read(t);
            add_edge(f, t, sz++);
            add_edge(t, f, sz++);
        }
        memset(paired, false, sizeof paired);
        odd = 0;
        dfs(1, 0);
        odd += !paired[1]; // 树根是否落单
        int num = (n - odd) / 2; // 成功配对的对数
        if(2 * num < k) // 配对点数不足 k
            ans = num + k - num * 2;
        else if(k & 1) // k 是奇数
            ans = k / 2 + 1;
        else // k 是偶数
            ans = k / 2;
        printf("%d\n", ans);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值