Acdream Cut 贪心

题意:给定一棵树(不一定是二叉树),现在问最多能够删除多少条边使得分开的结点满足分开子树的结点数都是偶数。

思路:首先用邻接表建立起一棵树,然后我们得出以下的结论:对于任意结点而言,如果该节点能够找出和与之相连的部分子树构成偶数个点并且这偶数个点不能再分解出偶数个结点的分支出来,那么这个点与其他相连的子树(没有加入前面的集合中)的边全部断掉。之所以可以断掉这些边是因为一个我们去掉的点集都是不能够再进行分割的集合,而且又达到了偶数个点,那么这偶数个点对于其他集合肯定也是没有帮助的,因为%2之后的贡献率为0。

代码如下:

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

struct Node {
    int x, next;
}e[200005];

int N, head[100005], idx, ret, sum[100005], hash[100005];

void insert(int x, int y) {
    ++idx;
    e[idx].x = y;
    e[idx].next = head[x];
    head[x] = idx;
}

int update(int x) {
    hash[x] = 1;
    if (head[x] == -1) {
        return sum[x] = 1;
    } else {
        sum[x] = 1;
        for (int i = head[x]; i != -1; i = e[i].next) {
            if (!hash[e[i].x]) {
                sum[x] += update(e[i].x);
            }
        }
        if (!(sum[x] & 1)) ++ret;
        return sum[x];
    }
}

int main() {
    int ans;
    while (scanf("%d", &N) == 1) {
        memset(head, 0xff, sizeof (head));
        memset(hash, 0, sizeof (hash));
        int x, y;
        idx = ret = -1;
        for (int i = 1; i < N; ++i) {
            scanf("%d %d", &x, &y); 
            insert(x, y); // 对这个树进行构边
            insert(y, x); // 构建的双向边
        }
        update(1);
        printf("%d\n", ret);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值