题解:#8911.集合问题 审核通过

Wind_Rises 砂糖老师 2025-03-02 13:26:52 2

初始化

  • 读取输入数据,并找出最大值 作为理想负荷。

  • 按照从大到小的顺序对数组进行排序。

贪心策略划分集合

  • 使用 小根堆 (priority_queue) 维护当前所有集合的负荷。

  • 依次将数字加入当前负荷最小的集合。

求最优

  • 遍历 ,计算每种情况的偏差之和。

  • 记录最小偏差,并在多个最优解中选择最大的

#include <bits/stdc++.h>
using namespace std;

vector<int> arr(1000); // 存储输入的整数

// 结构体表示一个集合的负荷
struct subset {
    int load;  // 当前负荷
    int idx;   // 集合索引(用于区分)
};

// 自定义比较函数,建立小根堆(负荷最小的集合优先)
struct cmp {
    bool operator()(const subset &a, const subset &b) const {
        return a.load > b.load;
    }
};

// 计算给定 N 和 M 时的偏差之和
int calculate(int N, int M) {
    priority_queue<subset, vector<subset>, cmp> minheap;
    // 初始化 N 个空集合
    for (int i = 0; i < N; i++) {
        minheap.push({ 0, i });
    }
    
    // 依次将数字分配给当前负荷最小的集合
    for (int i = 0; i < arr.size(); i++) {
        subset mintop = minheap.top(); // 取负荷最小的集合
        minheap.pop();
        mintop.load += arr[i]; // 加入当前整数
        minheap.push(mintop); // 放回堆中
    }
    
    // 计算所有集合的偏差之和
    int dev = 0;
    while (!minheap.empty()) {
        subset a = minheap.top();
        minheap.pop();
        dev += abs(a.load - M); // 计算偏差
    }
    return dev;
}

// 寻找使偏差最小的 N
int find_best_n() {
    sort(arr.rbegin(), arr.rend()); // 按降序排序
    int M = arr[0];  // 最大值 M
    int K = arr.size();
    
    int minD = INT_MAX; // 记录最小偏差
    int bestN = 0;
    
    for (int N = 1; N <= K; N++) {
        int dev = calculate(N, M);
        if (dev < minD) {
            minD = dev;
            bestN = N;
        } else if (dev == minD) {
            bestN = max(bestN, N); // 取最大的 N
        }
    }
    return bestN;
}

int main() {
    int K;
    cin >> K;
    for (int i = 0; i < K; i++) {
        cin >> arr[i];
    }
    cout << find_best_n() << endl;
    return 0;
}
{{ vote && vote.total.up }}