每日OJ题_牛客_分组_枚举+二分_C++_Java

目录

牛客_分组_枚举+二分

题目解析

C++代码

Java代码


牛客_分组_枚举+二分

分组 (nowcoder.com)

描述:

        dd当上了宣传委员,开始组织迎新晚会,已知班里有nnn个同学,每个同学有且仅有一个擅长的声部,把同学们分成恰好mmm组,为了不搞砸节目,每一组里的同学都必须擅长同一个声部,当然,不同组同学擅长同一个声部的情况是可以出现的,毕竟一个声部也可以分成好几个part进行表演,但是他不希望出现任何一组的人过多,否则可能会导致场地分配不协调,也就是说,她希望人数最多的小组的人尽可能少,除此之外,对组内人员分配没有其他要求,她希望你告诉她,这个值是多少,如果无法顺利安排,请输出-1。


题目解析

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

二分优化枚举:二分出符合要求的最大值。

C++代码

#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;
        // 		}
        // }
        // ⼆分解法
        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;
}

Java代码

import java.util.*;
public class Main
{
    public static int n, m;
    public static Map<Integer, Integer> hash = new HashMap<>(); // 统计每种声部的⼈数

    public static boolean check(int x) // 判断最多⼈数为 x 时,能否分成 m 组
    {
        int g = 0; // 统计能分成多少组
        for(int a : hash.values())
        {
            g += a / x + (a % x == 0 ? 0 : 1);
        }
        return g <= m;
    }

    public static void main(String[] args)
    {
        Scanner in = new Scanner(System.in);
        n = in.nextInt(); m = in.nextInt();
        int hmax = 0; // 所有声部的最⼤值
        for(int i = 0; i < n; i++)
        {
            int x = in.nextInt();
            hash.put(x, hash.getOrDefault(x, 0) + 1);
            hmax = Math.max(hmax, hash.get(x));
        }

        // 边界情况
        int kinds = hash.size();
        if(kinds > m)
        {
            System.out.println(-1);
        }
        else
        {
            // // 暴⼒解法
            // for(int i = 1; i <= hmax; i++)
            // {
            // 		if(check(i))
            // 		{
            // 			System.out.println(i);
            // 			break;
            // 		}
            // }
            // ⼆分解法
            int l = 1, r = hmax;
            while(l < r)
            {
                int mid = (l + r) / 2;
                if(check(mid))
                {
                    r = mid;
                }
                else
                {
                    l = mid + 1;
                }
            }
            System.out.println(l);
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

GR鲸鱼

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值