zoukankan      html  css  js  c++  java
  • 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;
    }
  • 相关阅读:
    第九周周记
    第七周周记
    第三次作业第一题
    第五周周记
    《世界是数字的》读后感想
    第十周周记
    迷茫
    测试作业
    价值观作业
    作业二 感想
  • 原文地址:https://www.cnblogs.com/Lyush/p/2775894.html
Copyright © 2011-2022 走看看