• 【并查集】C002_AW_樱桃网 & 打击犯罪(最下生成树 / dfs / 并查集求连通块)


    为了制作这道菜,他准备了N个樱桃,依次编号为1~N。
    在他的甜点中,任意两个樱桃之间都存在着一条用糖构成的链条,将它们直接互相连接。
    糖链呈红色或黑色,这取决于它们的含糖量。
    每条黑色糖链含有一个单位的糖,每条红色糖链含有两个单位的糖。
    在甜点完成之后,他发现甜点做的太甜了,而他的同学们都不喜欢吃含糖量过高的食物。
    请你帮助他找出他应该去掉哪些糖链,使得这道菜的每对樱桃之间都能通过糖链直接或间接连接的同时,含糖量能够尽可能的最低?
    输出这个含糖量的最小值。

    输入格式
    第一行包含整数T,表示共有T组测试数据。
    每组数据第一行包含两个整数N和M,分别表示樱桃数量以及黑色糖链数量。
    接下来M行,每行包含两个整数Ci和Di,表示编号为Ci和Di的两个樱桃之间存在一条黑色糖链。
    注意:如果任意两个樱桃之间,没有被黑色糖链连接,那么说明它们之间由一条红色糖链连接。
    输出格式
    每组数据输出一个结果,每个结果占一行。
    结果表示为“Case #x: y”,其中x是组别编号(从1开始),y为含糖量的最小值。
    数据范围
    1≤T≤100,
    M≤N∗(N−1)/2
    1≤Ci,Di≤N,
    Ci≠Di,
    同一组数据内,所有{Ci, Di}对都互不相同。
    1≤N≤105,
    0≤M≤105

    输入样例:
    2
    2 1
    1 2
    3 1
    2 3
    输出样例:
    Case #1: 1
    Case #2: 3
    样例解释
    在样例#1中,只有两个樱桃,它们之间由一个黑色糖链连接,去掉任何糖链都会使樱桃之间断连。
    所以,含糖量的最小值为1。
    在样例#2中,一种可行的方法是保留1和2之间的红色糖链以及2和3之间的黑色糖链。
    所以,含糖量的最小值为3
    

    方法一:连通块

    
    

    二、打击犯罪

    某个地区有 n 个犯罪团伙,当地警方按照他们的危险程度由高到低给他们编号为 1∼n。
    他们有些团伙之间有直接联系,但是任意两个团伙都可以通过直接或间接的方式联系。
    所有可直接或间接联系的团伙被称为一个犯罪集团。犯罪集团的危险程度由集团内的犯罪团伙数量唯一确定,而与单个犯罪团伙的危险程度无关(该犯罪集团的危险程度为 n)。
    现在当地警方希望花尽量少的时间(即打击掉尽量少的团伙),使得庞大的犯罪集团分离成若干个较小的集团,并且他们中最大的一个的危险程度不超过 n/2。
    为达到最好的效果,他们将按顺序打击掉编号 1 到 k 的犯罪团伙,请编程求出 k 的最小值。
    注意: 数据保证至少存在一个犯罪集团的危险程度超过 n/2。
    输入格式
    第一行一个正整数 n。
    接下来的 n 行每行有若干个正整数,第一个整数表示该行除第一个外还有多少个整数,若第 i 行存在正整数 k,表示 i,k 两个团伙可以直接联系。
    输出格式
    一个正整数,为 k 的最小值。
    数据范围
    1≤n≤1000

    输入样例:
    7
    2 2 5
    3 1 3 4
    2 2 4
    2 2 3
    3 1 6 7
    2 5 7
    2 5 6
    输出样例:
    1
    

    方法一:邻接表+并查集

    将单个团伙的危险程度理解成团伙人数,然后一个团伙有多个邻邦,团伙和其邻邦的总人数即为危险程度

    题目要求顺序打击,这一点可以配合反向思维来做,先打击第 n-i 到 第 n 个团伙:

    • 如果此时这些团伙的总危险程度 \(>\cfrac{n}{2}\),则前面的 1~i 个集团一定不超过 \(\cfrac{n}{2}\)
    • 反之我还可继续缩减 i

    注:顺序打击意味着第 i 个团伙后序的团伙的编号 x 必须大于 i,而如果 x≤i 即使他们有联系,也不能打击 x

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N=1e3+5;
    int fa[N], sz[N];
    vector<int> g[N];
    
    int find(int u) {
        return fa[u]==u ? u : fa[u]=find(fa[u]);
    }
    int main() {
        std::ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
        int n; cin>>n;
    
        for (int i=1; i<=n; i++) {
            int m, x; cin>>m, fa[i]=i, sz[i]=1;
            for (int j=1; j<=m; j++)
                cin>>x, g[i].push_back(x); 
        }
        
        for (int i=n; i>0; i--)
        for (int x : g[i]) if (x>i) {
            int fi=find(i), fx=find(x);
            if (fi!=fx) {
                fa[fi]=fx;
                sz[fx]+=sz[fi];
                if (sz[fx]>(n>>1)) {
                    return cout << i, 0;
                }
            }
        }
        return 0;
    }
    
  • 相关阅读:
    卡诺图简单逻辑化简与五变量卡诺图化简
    flash读写学习笔记与spi接口及简单测试验证(三)
    疯狂的订餐系统软件需求分析挑战之旅4
    .NET(C#):谈谈各种结束进程的方法
    疯狂的订餐系统软件需求分析挑战之旅3
    疯狂的订餐系统软件需求分析挑战之旅5
    找零
    ASP.NET MVC3 Razor视图引擎基础语法
    做了8年软件开发了,年龄大了,想要转行做测试,大家给点意见
    想搞一个 代码仓库的东西,不知道大家有没有兴趣啊
  • 原文地址:https://www.cnblogs.com/wdt1/p/13645734.html
Copyright © 2020-2023  润新知