【编程题-错题集】分组(枚举 + 二分)

简介: 【编程题-错题集】分组(枚举 + 二分)

牛客对应题目链接:分组 (nowcoder.com)


一、分析题目

1、暴力枚举

从小到大枚举所有可能的最大值,找到第⼀个符合要求的最大值。

  1. 统计出每一种声部的人数:hash。
  2. 枚举最终的分配结果中,最多的人数(x),从小到大枚举 1~hmax


2、二分优化枚举

利用二段性,⼆分出符合要求的最大值。


二、代码

1、方法一(暴力枚举)

#include <iostream>
#include <unordered_map>
 
using namespace std;
 
int n, m;
unordered_map<int, int> cnt; // 统计每种声部的⼈数
 
bool check(int x) // 判断最多⼈数为 x 时,能否分成 m 组
{
    int g = 0; // 能分成多少组
    for(auto& [a, b] : cnt)
    {
        g += b / x + (b % x == 0 ? 0 : 1);
    }
    return g <= m;
}
 
int main()
{
    cin >> n >> m;
    int hmax = 0; // 统计声部最多的⼈数
    for(int i = 0; i < n; i++)
    {
        int x;
        cin >> x;
        hmax = max(hmax, ++cnt[x]);
    }
 
    int kinds = cnt.size();
    if(kinds > m) // 处理边界情况
    {
        cout << -1 << endl;
    }
    else
    {        
        // 暴⼒枚举
        for(int i = 1; i <= hmax; i++) // 枚举所有的最多⼈数
        {
            if(check(i))
            {
                cout << i << endl;
                break;
            }
        }
    }
 
    return 0;
}

2、方法二(二分)

#include <iostream>
#include <unordered_map>
 
using namespace std;
 
int n, m;
unordered_map<int, int> cnt; // 统计每种声部的⼈数
 
bool check(int x) // 判断最多⼈数为 x 时,能否分成 m 组
{
    int g = 0; // 能分成多少组
    for(auto& [a, b] : cnt)
    {
        g += b / x + (b % x == 0 ? 0 : 1);
    }
    return g <= m;
}
 
int main()
{
    cin >> n >> m;
    int hmax = 0; // 统计声部最多的⼈数
    for(int i = 0; i < n; i++)
    {
        int x;
        cin >> x;
        hmax = max(hmax, ++cnt[x]);
    }
 
    int kinds = cnt.size();
    if(kinds > m) // 处理边界情况
    {
        cout << -1 << endl;
    }
    else
    {        
        // ⼆分解法
        int l = 1, r = hmax;
        while(l < r)
        {
            int mid = (l + r) / 2;
            if(check(mid)) r = mid;
            else l = mid + 1;
        }
        cout << l << endl;
    }
 
    return 0;
}

三、反思与改进

这道题的暴力枚举思路基本正确,也想到了如何去分组才是正确的,不过没有理清楚在什么样的情况下会输出 -1 以及如何 +1 个分组的写法。虽然这道题目的暴力解法可以通过,但还是需要掌握二分优化的写法,发现自己虽然会写二分,但是对于二分的运用还是没有什么思路上的框架,下次遇到需要 check 的题目就往二分上想一想,看看能不能找出其中的二段性。


相关文章
|
项目管理
中项案例分析题
案例分析题
67 1
|
7月前
|
C语言
c语言编程练习题:7-51 求奇数分之一序列前N项和
c语言编程练习题:7-51 求奇数分之一序列前N项和
79 0
|
7月前
|
C语言
c语言编程练习题:7-52 求简单交错序列前N项和
c语言编程练习题:7-52 求简单交错序列前N项和
68 0
|
6月前
|
移动开发 C++
【洛谷 P1157】组合的输出 题解(深度优先搜索+枚举子集)
该问题要求编程输出从1到n中选择r个元素的所有组合,组合按字典序排列。输入包含两自然数n和r(1&lt;n&lt;21, 0≤r≤n)。输出每个组合时,每个数字占据3个字符宽度。提供的AC代码使用C++,通过递归搜索方法枚举子集。样例输入为5 3,输出显示所有3个元素的组合。
55 0
|
7月前
【错题集-编程题】排序子序列(模拟)
【错题集-编程题】排序子序列(模拟)
|
7月前
|
C语言
c语言编程练习题:7-32 求交错序列前N项和
c语言编程练习题:7-32 求交错序列前N项和
137 0
|
算法
代码随想录算法训练营第二十六天 | LeetCode 39. 组合总和、40. 组合总和 II、131. 分割回文串
代码随想录算法训练营第二十六天 | LeetCode 39. 组合总和、40. 组合总和 II、131. 分割回文串
53 0
|
存储 算法 容器
精选算法题(1)——枚举符合要求的算术表达式(DFS、回溯法)
精选算法题(1)——枚举符合要求的算术表达式(DFS、回溯法)
|
人工智能 算法 测试技术
[蓝桥杯] 枚举、模拟和排列问题
[蓝桥杯] 枚举、模拟和排列问题
83 0