华为OD机试 - 最旺店铺 - 枚举(Python/JS/C/C++ 2025 B卷 200分)

在这里插入图片描述

2025B卷华为OD机试统一考试题库清单(持续收录中)以及考点说明(Python/JS/C/C++)

专栏导读

本专栏收录于《华为OD机试真题(Python/JS/C/C++)》

刷的越多,抽中的概率越大,私信哪吒,备注华为OD,加入华为OD刷题交流群,每一题都有详细的答题思路、详细的代码注释、3个测试用例、为什么这道题采用XX算法、XX算法的适用场景,发现新题目,随时更新。

一、题目描述

某城市有m个商店和n位市民。

现在要举办一场活动,通过投票来选出最受欢迎的商店。

每位市民只能投一票,他们将根据自己的喜好为指定的商店投票。

然而,1号商店有一个特殊的优势,它可以给每位市民发放补贴,使他们改变投票意向,投票给1号商店。

请你计算出,1号商店为了成为最受欢迎的商店(即获得的票数超过其它所有商店),需要发放多少金额的补贴。

如果1号商店已经是最受欢迎的商店,则输出0。

二、输入描述

第一行输入两个整数n和m,以逗号隔开,分别表示市民总数和商店总数。1 <= n,m <= 3000。

接下来的n行,每行输出两个整数p和q,以逗号隔开,其中p表示该市民初步想要投票给p号商店,q表示为了让该市民改投1号商店需要支付的补贴金额。

三、输出描述

输出一个整数,表示1号商店为了成为最受欢迎的商店,需要发放的最少补贴金额。

四、测试用例

测试用例1

1、输入

5,5
2,10
3,20
4,30
5,40
5,90

2、输出

50

3、说明

如果选择发放10+20+30,抢2、3、4号店铺手中的票,总共需要发放60元补贴(5号店铺2票、1号店铺3票,1号店铺胜出)
如果选择发放10+40,抢2、5号店铺手中的票,总共需要发放50元补贴(5号店铺1票、1号店铺2票,1号店铺胜出)
所以最少发放50元补贴

测试用例2

1、输入

5,5
2,10
3,20
4,30
5,80
5,90

2、输出

60

3、说明

选择发放10+20+30,抢2、3、4号店铺手中的票,总共需要发放60元补贴(5号店铺2票、1号店铺3票,1号店铺胜出)
所以最少发放60元补贴

五、解题思路

核心思想是迭代1号商店最终可能达成的“获胜票数”,我们称之为 targetS1FinalVotes。这个目标票数 X 的范围是从1到市民总数 n。对于每一个可能的 X:

  1. 初始化:
    • currentSubsidyForThisTarget = 0: 当前目标 X 下的总补贴。
    • currentS1AcquiredVotes = initialStore1Votes: 1号商店当前拥有的票数,初始为其原始票数。
    • bribedCitizenIdsInThisRound = new HashSet<>(): 清空已拉拢市民集合。
  2. 确保其他商店票数达标
    • 目标是让1号商店以 X 票获胜,这意味着其他所有商店 j ( j != 1) 的票数必须严格少于 X,即最多只能有 X-1 票。
    • 遍历每个其他商店 j:
    • 计算商店 j 当前拥有的(未被拉拢的)票数。
    • 如果商店 j 的票数 count_j >= X,则必须从商店 j 拉拢 count_j - (X - 1) 个市民。
    • 从 votersPerOtherStore[j](已按补贴金额排序)中选择补贴金额最低的、且尚未被拉拢的市民进行拉拢。
    • 累加补贴金额到 currentSubsidyForThisTarget,增加 currentS1AcquiredVotes,并将被拉拢市民的ID加入 bribedCitizenIdsInThisRound。
  3. 收集可供进一步拉拢的市民
    • 创建一个临时的市民列表 availablePoolForBribing。
    • 遍历所有市民 (allCitizens),如果一个市民最初不投给1号店,并且在阶段一中没有被拉拢 (即其ID不在 bribedCitizenIdsInThisRound 中),则将其加入 availablePoolForBribing。
    • 按补贴金额 subsidyCost 对 availablePoolForBribing 排序。
  4. 确保1号商店达到目标票数 X
    • 计算1号商店还需要 additionalVotesNeededForS1 = X - currentS1AcquiredVotes 票。
    • 如果 additionalVotesNeededForS1 > 0:
    • 检查 availablePoolForBribing 中的人数是否足够。如果不足,则当前目标 X 无法实现,跳过此 X,继续下一个 X 的迭代。
    • 从 availablePoolForBribing 中选择补贴金额最低的 additionalVotesNeededForS1 个市民进行拉拢。
    • 累加补贴金额,增加 currentS1AcquiredVotes。
  5. 更新最小总补贴:
    • 在此轮迭代(针对特定 X)结束后,如果 currentS1AcquiredVotes >= X(表示1号商店达到了目标票数),并且通过阶段一的操作确保了其他所有商店的票数都严格小于 X,那么 currentSubsidyForThisTarget 就是一个可能的有效补贴总额。
    • 用 currentSubsidyForThisTarget 更新 minOverallSubsidy = Math.min(minOverallSubsidy, currentSubsidyForThisTarget)。
  6. 初始状态检查:
    • 在主循环开始前,先计算所有商店的初始票数。
    • 如果1号商店的初始票数已经严格大于其他任何商店的票数(或者如果只有1个商店,或者没有市民),则最少补贴为0,直接输出并结束程序。
  7. 特殊情况处理:
    • 如果 m=1(只有一个商店),则1号商店自然最受欢迎,成本为0。
    • 题目约束 1 <= n, m,所以 n=0 的情况不会出现。

六、Python算法源码

# -*- coding: utf-8 -*-

# 定义市民类
class Citizen:
    def __init__(self, id, initial_store, subsidy_cost):
        self.id = id  # 市民的原始索引/编号
        self.initial_store = initial_store  # 市民初始投票的商店编号
        self.subsidy_cost = subsidy_cost  # 让该市民改投1号商店需要支付的补贴金额

    def __lt__(self, other): # 用于排序,按补贴金额升序
        return self.subsidy_cost < other.subsidy_cost

def solve():
    # 读取市民总数n和商店总数m
    n_str, m_str = input().split(',')
    n = int(n_str)
    m = int(m_str)

    # 如果只有一个商店,那么1号商店自然最受欢迎,无需补贴
    if m == 1:
        print(0)
        return

    all_citizens = [] # 存储所有市民的详细信息
    # 字典,键是商店ID,值是该商店的投票者列表 (Citizen对象)
    voters_per_other_store = {} 
    for i in range(2, m + 1):
        voters_per_other_store[i] = []

    initial_store1_votes = 0 # 记录1号商店的初始票数

    # 读取n行市民的投票意向和补贴金额
    for i in range(n):
        p_str, q_str = input().split(',')
        p = int(p_str)  # 商店编号
        q = int(q_str)  # 补贴金额
        citizen = Citizen(i, p, q)
        all_citizens.append(citizen)

        if p == 1:
            initial_store1_votes += 1
        else:
            if p in voters_per_other_store: # 确保商店p存在于字典中
                 voters_per_other_store[p].append(citizen)


    # 对每个非1号商店的投票者按补贴金额升序排序
    for store_id in voters_per_other_store:
        voters_per_other_store[store_id].sort()

    # 检查1号商店是否已经是最受欢迎的
    current_total_votes = [0] * (m + 1) # 索引0不用,从1到m
    for c in all_citizens:
        current_total_votes[c.initial_store] += 1

    max_other_store_initial_votes = 0
    if m > 1:
        for j in range(2, m + 1):
            max_other_store_initial_votes = max(max_other_store_initial_votes, current_total_votes[j])
    
    if n == 0: # 题目约束 n >= 1
        print(0)
        return
        
    # (m == 1) 的情况已在前面处理
    # 如果1号商店票数已严格大于其他任何商店 (且至少有两个商店参与比较)
    if (current_total_votes[1] > max_other_store_initial_votes and m > 1):
        print(0)
        return

    min_overall_subsidy = float('inf') # 初始化为正无穷大

    # 迭代1号商店最终可能获得的票数 X (从1到n)
    for target_s1_final_votes in range(1, n + 1):
        current_subsidy_for_this_target = 0
        current_s1_acquired_votes = initial_store1_votes
        bribed_citizen_ids_in_this_round = set() # 记录本轮已拉拢市民的ID

        # 阶段1: 强制拉拢,确保其他商店的票数严格小于 target_s1_final_votes
        for store_idx in range(2, m + 1):
            # 计算 store_idx 当前未被拉拢的票数
            # voters_per_other_store[store_idx] 是初始投给 store_idx 的人,已排序
            
            # 统计当前有效的(未被本轮拉拢的)投票给 store_idx 的人数
            current_votes_for_store_idx = 0
            potential_bribes_from_this_store = [] # 收集本店可被拉拢的市民(未被本轮拉拢过)
            
            # 遍历最初投给该商店的市民
            original_voters_of_store = voters_per_other_store.get(store_idx, [])
            for c_original in original_voters_of_store:
                if c_original.id not in bribed_citizen_ids_in_this_round:
                    current_votes_for_store_idx +=1
                    potential_bribes_from_this_store.append(c_original)
            # potential_bribes_from_this_store 已经是按成本排序的

            num_to_bribe_mandatorily = current_votes_for_store_idx - (target_s1_final_votes - 1)

            if num_to_bribe_mandatorily > 0:
                bribed_count_from_store = 0
                for k in range(len(potential_bribes_from_this_store)):
                    if bribed_count_from_store >= num_to_bribe_mandatorily:
                        break
                    citizen_to_bribe = potential_bribes_from_this_store[k]
                    # 确保没有重复拉拢(理论上potential_bribes_from_this_store已过滤)
                    if citizen_to_bribe.id not in bribed_citizen_ids_in_this_round:
                        current_subsidy_for_this_target += citizen_to_bribe.subsidy_cost
                        current_s1_acquired_votes += 1
                        bribed_citizen_ids_in_this_round.add(citizen_to_bribe.id)
                        bribed_count_from_store +=1
        
        # 阶段 2: 收集所有还未被拉拢的、且初始不投给1号店的市民
        available_pool_for_bribing = []
        for citizen in all_citizens:
            if citizen.initial_store != 1 and citizen.id not in bribed_citizen_ids_in_this_round:
                available_pool_for_bribing.append(citizen)
        available_pool_for_bribing.sort() # 按补贴金额排序

        # 阶段 3: 如果1号商店的票数仍未达到 target_s1_final_votes
        additional_votes_needed_for_s1 = target_s1_final_votes - current_s1_acquired_votes
        if additional_votes_needed_for_s1 > 0:
            if additional_votes_needed_for_s1 > len(available_pool_for_bribing):
                continue # 此 targetS1FinalVotes 不可行

            for k in range(additional_votes_needed_for_s1):
                citizen_to_bribe = available_pool_for_bribing[k]
                current_subsidy_for_this_target += citizen_to_bribe.subsidy_cost
                current_s1_acquired_votes += 1
                # bribed_citizen_ids_in_this_round.add(citizen_to_bribe.id) # 此处加不加都行,因为是从池里拿的
        
        # 检查最终条件
        if current_s1_acquired_votes >= target_s1_final_votes:
            condition_met = True
            for store_idx_check in range(2, m + 1):
                other_store_final_votes = 0
                original_voters_list = voters_per_other_store.get(store_idx_check, [])
                for c_original in original_voters_list:
                    if c_original.id not in bribed_citizen_ids_in_this_round:
                        other_store_final_votes += 1
                
                if other_store_final_votes >= target_s1_final_votes:
                    condition_met = False
                    break
            
            if condition_met:
                min_overall_subsidy = min(min_overall_subsidy, current_subsidy_for_this_target)

    print(min_overall_subsidy if min_overall_subsidy != float('inf') else 0)


solve()


七、JavaScript算法源码

// JavaScript (Node.js environment for console input/output)

// 定义市民类
class Citizen {
    constructor(id, initialStore, subsidyCost) {
        this.id = id; // 市民的原始索引/编号
        this.initialStore = initialStore; // 市民初始投票的商店编号
        this.subsidyCost = subsidyCost; // 让该市民改投1号商店需要支付的补贴金额
    }
}

// 用于排序Citizen对象的比较函数
function compareCitizens(a, b) {
    return a.subsidyCost - b.subsidyCost;
}

function solve() {
    const readline = require('readline');
    const rl = readline.createInterface({
        input: process.stdin,
        output: process.stdout,
        terminal: false
    });

    let inputLines = [];
    rl.on('line', (line) => {
        inputLines.push(line);
    });

    rl.on('close', () => {
        const [nStr, mStr] = inputLines[0].split(',');
        const n = parseInt(nStr); // 市民总数
        const m = parseInt(mStr); // 商店总数

        if (m === 1) {
            console.log(0);
            return;
        }

        let allCitizens = []; // 存储所有市民的详细信息
        // 对象,键是商店ID (字符串形式),值是该商店的投票者列表 (Citizen对象)
        let votersPerOtherStore = {}; 
        for (let i = 2; i <= m; i++) {
            votersPerOtherStore[i.toString()] = [];
        }

        let initialStore1Votes = 0; // 记录1号商店的初始票数

        for (let i = 0; i < n; i++) {
            const [pStr, qStr] = inputLines[i + 1].split(',');
            const p = parseInt(pStr); // 商店编号
            const q = parseInt(qStr); // 补贴金额
            const citizen = new Citizen(i, p, q);
            allCitizens.push(citizen);

            if (p === 1) {
                initialStore1Votes++;
            } else {
                if (votersPerOtherStore[p.toString()]) {
                     votersPerOtherStore[p.toString()].push(citizen);
                }
            }
        }

        for (let storeIdKey in votersPerOtherStore) {
            votersPerOtherStore[storeIdKey].sort(compareCitizens);
        }
        
        let currentTotalVotes = new Array(m + 1).fill(0);
        for (const c of allCitizens) {
            currentTotalVotes[c.initialStore]++;
        }

        let maxOtherStoreInitialVotes = 0;
        if (m > 1) {
            for (let j = 2; j <= m; j++) {
                maxOtherStoreInitialVotes = Math.max(maxOtherStoreInitialVotes, currentTotalVotes[j]);
            }
        }

        if (n === 0) { // 题目约束 n >= 1
             console.log(0);
             return;
        }

        if (currentTotalVotes[1] > maxOtherStoreInitialVotes && m > 1) {
            console.log(0);
            return;
        }

        let minOverallSubsidy = Infinity; // 初始化为正无穷大

        for (let targetS1FinalVotes = 1; targetS1FinalVotes <= n; targetS1FinalVotes++) {
            let currentSubsidyForThisTarget = 0;
            let currentS1AcquiredVotes = initialStore1Votes;
            let bribedCitizenIdsInThisRound = new Set();

            for (let storeIdx = 2; storeIdx <= m; storeIdx++) {
                let currentVotesForStoreIdx = 0;
                let potentialBribesFromThisStore = [];
                
                const originalVotersOfStore = votersPerOtherStore[storeIdx.toString()] || [];
                for (const c_original of originalVotersOfStore) {
                    if (!bribedCitizenIdsInThisRound.has(c_original.id)) {
                        currentVotesForStoreIdx++;
                        potentialBribesFromThisStore.push(c_original);
                    }
                }
                // potentialBribesFromThisStore is already sorted if original was

                let numToBribeMandatorily = currentVotesForStoreIdx - (targetS1FinalVotes - 1);

                if (numToBribeMandatorily > 0) {
                    let bribedCountFromStore = 0;
                    for (let k = 0; k < potentialBribesFromThisStore.length; k++) {
                        if (bribedCountFromStore >= numToBribeMandatorily) break;
                        const citizenToBribe = potentialBribesFromThisStore[k];
                        if (!bribedCitizenIdsInThisRound.has(citizenToBribe.id)) {
                            currentSubsidyForThisTarget += citizenToBribe.subsidyCost;
                            currentS1AcquiredVotes++;
                            bribedCitizenIdsInThisRound.add(citizenToBribe.id);
                            bribedCountFromStore++;
                        }
                    }
                }
            }

            let availablePoolForBribing = [];
            for (const citizen of allCitizens) {
                if (citizen.initialStore !== 1 && !bribedCitizenIdsInThisRound.has(citizen.id)) {
                    availablePoolForBribing.push(citizen);
                }
            }
            availablePoolForBribing.sort(compareCitizens);

            let additionalVotesNeededForS1 = targetS1FinalVotes - currentS1AcquiredVotes;
            if (additionalVotesNeededForS1 > 0) {
                if (additionalVotesNeededForS1 > availablePoolForBribing.length) {
                    continue;
                }
                for (let k = 0; k < additionalVotesNeededForS1; k++) {
                    const citizenToBribe = availablePoolForBribing[k];
                    currentSubsidyForThisTarget += citizenToBribe.subsidyCost;
                    currentS1AcquiredVotes++;
                }
            }

            if (currentS1AcquiredVotes >= targetS1FinalVotes) {
                let conditionMet = true;
                for (let storeIdxCheck = 2; storeIdxCheck <= m; storeIdxCheck++) {
                    let otherStoreFinalVotes = 0;
                    const originalVotersList = votersPerOtherStore[storeIdxCheck.toString()] || [];
                    for (const c_original of originalVotersList) {
                        if (!bribedCitizenIdsInThisRound.has(c_original.id)) {
                            otherStoreFinalVotes++;
                        }
                    }
                    if (otherStoreFinalVotes >= targetS1FinalVotes) {
                        conditionMet = false;
                        break;
                    }
                }
                if (conditionMet) {
                    minOverallSubsidy = Math.min(minOverallSubsidy, currentSubsidyForThisTarget);
                }
            }
        }
        console.log(minOverallSubsidy === Infinity ? 0 : minOverallSubsidy);
    });
}

solve();

八、C算法源码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h> // For LONG_MAX or LLONG_MAX

// 定义市民结构体
typedef struct {
    int id;             // 市民的原始索引/编号
    int initial_store;  // 市民初始投票的商店编号
    int subsidy_cost;   // 让该市民改投1号商店需要支付的补贴金额
} Citizen;

// 用于qsort的比较函数,按补贴金额升序
int compare_citizens(const void *a, const void *b) {
    Citizen *cA = (Citizen *)a;
    Citizen *cB = (Citizen *)b;
    return cA->subsidy_cost - cB->subsidy_cost;
}

// 辅助函数:检查一个id是否在集合(用数组模拟)中
int is_in_set(int id, const int *set_array, int set_size) {
    for (int i = 0; i < set_size; i++) {
        if (set_array[i] == id) {
            return 1; // 存在
        }
    }
    return 0; // 不存在
}

// 辅助函数:向集合(用数组模拟)中添加id
// 返回新的集合大小
int add_to_set(int id, int *set_array, int current_set_size, int max_set_size) {
    if (!is_in_set(id, set_array, current_set_size) && current_set_size < max_set_size) {
        set_array[current_set_size] = id;
        return current_set_size + 1;
    }
    return current_set_size;
}


int main() {
    int n, m; // 市民总数n和商店总数m
    if (scanf("%d,%d\n", &n, &m) != 2) return 1; // 读取n, m

    if (m == 1) {
        printf("0\n");
        return 0;
    }

    Citizen *all_citizens = (Citizen *)malloc(n * sizeof(Citizen)); // 存储所有市民信息
    if (!all_citizens) return 1;

    // voters_per_other_store[store_id] 是一个指向 Citizen 数组的指针
    // counts_per_other_store[store_id] 是该数组中的市民数量
    Citizen **voters_per_other_store = (Citizen **)malloc((m + 1) * sizeof(Citizen *));
    int *counts_per_other_store = (int *)calloc(m + 1, sizeof(int)); // 初始化为0
    int *capacities_per_other_store = (int *)calloc(m + 1, sizeof(int)); // 动态数组容量
    
    if (!voters_per_other_store || !counts_per_other_store || !capacities_per_other_store) {
        // 释放已分配内存
        free(all_citizens);
        if (voters_per_other_store) {
            for(int i=2; i<=m; ++i) free(voters_per_other_store[i]);
            free(voters_per_other_store);
        }
        free(counts_per_other_store);
        free(capacities_per_other_store);
        return 1;
    }

    for (int i = 2; i <= m; i++) { // 初始化其他商店的投票者列表
        capacities_per_other_store[i] = 10; // 初始容量
        voters_per_other_store[i] = (Citizen *)malloc(capacities_per_other_store[i] * sizeof(Citizen));
        if (!voters_per_other_store[i]) { /* ... 错误处理和内存释放 ... */ return 1;}
        counts_per_other_store[i] = 0;
    }

    int initial_store1_votes = 0; // 1号店初始票数

    for (int i = 0; i < n; i++) {
        int p, q;
        if (scanf("%d,%d\n", &p, &q) != 2) { /* ... 错误处理 ... */ return 1; }
        all_citizens[i].id = i;
        all_citizens[i].initial_store = p;
        all_citizens[i].subsidy_cost = q;

        if (p == 1) {
            initial_store1_votes++;
        } else if (p >=2 && p <= m) { // 只处理有效范围内的其他商店
            if (counts_per_other_store[p] >= capacities_per_other_store[p]) {
                capacities_per_other_store[p] *= 2;
                Citizen* temp = (Citizen *)realloc(voters_per_other_store[p], capacities_per_other_store[p] * sizeof(Citizen));
                if(!temp) { /* ... 错误处理 ... */ return 1; }
                voters_per_other_store[p] = temp;
            }
            voters_per_other_store[p][counts_per_other_store[p]++] = all_citizens[i];
        }
    }

    for (int i = 2; i <= m; i++) { // 排序
        if(counts_per_other_store[i] > 0) {
            qsort(voters_per_other_store[i], counts_per_other_store[i], sizeof(Citizen), compare_citizens);
        }
    }

    int *current_total_votes = (int *)calloc(m + 1, sizeof(int));
    if(!current_total_votes) { /* ... 错误处理 ... */ return 1; }
    for (int i = 0; i < n; i++) {
        current_total_votes[all_citizens[i].initial_store]++;
    }

    int max_other_store_initial_votes = 0;
    if (m > 1) {
        for (int j = 2; j <= m; j++) {
            if (current_total_votes[j] > max_other_store_initial_votes) {
                max_other_store_initial_votes = current_total_votes[j];
            }
        }
    }
    
    if (n == 0) { // 题目约束 n >= 1
         printf("0\n");
         // ... 释放所有动态内存 ...
         return 0;
    }

    if ((current_total_votes[1] > max_other_store_initial_votes && m > 1)) {
        printf("0\n");
        // ... 释放所有动态内存 ...
        return 0;
    }

    long long min_overall_subsidy = LLONG_MAX; // 使用 long long 存储补贴总额
    int *bribed_citizen_ids_in_this_round_arr = (int *)malloc(n * sizeof(int)); // 模拟Set
    Citizen *available_pool_for_bribing_arr = (Citizen *)malloc(n * sizeof(Citizen)); // 模拟List
    if(!bribed_citizen_ids_in_this_round_arr || !available_pool_for_bribing_arr) { /* ... 错误处理 ... */ return 1; }


    for (int target_s1_final_votes = 1; target_s1_final_votes <= n; target_s1_final_votes++) {
        long long current_subsidy_for_this_target = 0;
        int current_s1_acquired_votes = initial_store1_votes;
        int bribed_ids_count_this_round = 0; // 当前轮已拉拢市民数量

        for (int store_idx = 2; store_idx <= m; store_idx++) {
            int current_votes_for_store_idx = 0;
            Citizen temp_potential_bribes[n]; // 假设n是最大可能数量
            int temp_potential_bribes_count = 0;

            for(int k=0; k < counts_per_other_store[store_idx]; ++k) {
                Citizen c_original = voters_per_other_store[store_idx][k];
                if (!is_in_set(c_original.id, bribed_citizen_ids_in_this_round_arr, bribed_ids_count_this_round)) {
                    current_votes_for_store_idx++;
                    if (temp_potential_bribes_count < n) { // 防止溢出
                        temp_potential_bribes[temp_potential_bribes_count++] = c_original;
                    }
                }
            }
            // temp_potential_bribes 已经是按成本排序的(因为源voters_per_other_store[store_idx]是)

            int num_to_bribe_mandatorily = current_votes_for_store_idx - (target_s1_final_votes - 1);

            if (num_to_bribe_mandatorily > 0) {
                int bribed_count_from_store = 0;
                for (int k = 0; k < temp_potential_bribes_count; k++) {
                    if (bribed_count_from_store >= num_to_bribe_mandatorily) break;
                    Citizen citizen_to_bribe = temp_potential_bribes[k];
                     if (!is_in_set(citizen_to_bribe.id, bribed_citizen_ids_in_this_round_arr, bribed_ids_count_this_round)) {
                        current_subsidy_for_this_target += citizen_to_bribe.subsidy_cost;
                        current_s1_acquired_votes++;
                        bribed_ids_count_this_round = add_to_set(citizen_to_bribe.id, bribed_citizen_ids_in_this_round_arr, bribed_ids_count_this_round, n);
                        bribed_count_from_store++;
                    }
                }
            }
        }
        
        int available_pool_count = 0;
        for (int i = 0; i < n; i++) {
            if (all_citizens[i].initial_store != 1 && !is_in_set(all_citizens[i].id, bribed_citizen_ids_in_this_round_arr, bribed_ids_count_this_round)) {
                if (available_pool_count < n) { // 防止溢出
                     available_pool_for_bribing_arr[available_pool_count++] = all_citizens[i];
                }
            }
        }
        if (available_pool_count > 0) {
            qsort(available_pool_for_bribing_arr, available_pool_count, sizeof(Citizen), compare_citizens);
        }
        

        int additional_votes_needed_for_s1 = target_s1_final_votes - current_s1_acquired_votes;
        if (additional_votes_needed_for_s1 > 0) {
            if (additional_votes_needed_for_s1 > available_pool_count) {
                continue;
            }
            for (int k = 0; k < additional_votes_needed_for_s1; k++) {
                Citizen citizen_to_bribe = available_pool_for_bribing_arr[k];
                current_subsidy_for_this_target += citizen_to_bribe.subsidy_cost;
                current_s1_acquired_votes++;
                // 不再需要添加到bribed_citizen_ids_in_this_round_arr,因为池已过滤
            }
        }

        if (current_s1_acquired_votes >= target_s1_final_votes) {
            int condition_met = 1;
            for (int store_idx_check = 2; store_idx_check <= m; store_idx_check++) {
                int other_store_final_votes = 0;
                for(int k=0; k < counts_per_other_store[store_idx_check]; ++k) {
                    Citizen c_original = voters_per_other_store[store_idx_check][k];
                    if (!is_in_set(c_original.id, bribed_citizen_ids_in_this_round_arr, bribed_ids_count_this_round)) {
                        other_store_final_votes++;
                    }
                }
                if (other_store_final_votes >= target_s1_final_votes) {
                    condition_met = 0;
                    break;
                }
            }
            if (condition_met) {
                if (current_subsidy_for_this_target < min_overall_subsidy) {
                    min_overall_subsidy = current_subsidy_for_this_target;
                }
            }
        }
    }

    printf("%lld\n", min_overall_subsidy == LLONG_MAX ? 0 : min_overall_subsidy);

    // 释放所有动态分配的内存
    free(all_citizens);
    for (int i = 2; i <= m; i++) {
        free(voters_per_other_store[i]);
    }
    free(voters_per_other_store);
    free(counts_per_other_store);
    free(capacities_per_other_store);
    free(current_total_votes);
    free(bribed_citizen_ids_in_this_round_arr);
    free(available_pool_for_bribing_arr);

    return 0;
}

九、C++算法源码

#include <iostream>
#include <vector>
#include <string>
#include <sstream>
#include <algorithm>
#include <set>
#include <map> // 用于 voters_per_other_store

// 定义市民结构体
struct Citizen {
    int id;             // 市民的原始索引/编号
    int initial_store;  // 市民初始投票的商店编号
    int subsidy_cost;   // 让该市民改投1号商店需要支付的补贴金额

    // 为了排序,重载小于操作符
    bool operator<(const Citizen& other) const {
        return subsidy_cost < other.subsidy_cost;
    }
};

// 从字符串中解析逗号分隔的整数
std::pair<int, int> parse_pair(const std::string& s) {
    std::stringstream ss(s);
    std::string segment;
    int val1, val2;
    std::getline(ss, segment, ',');
    val1 = std::stoi(segment);
    std::getline(ss, segment, ',');
    val2 = std::stoi(segment);
    return {val1, val2};
}

int main() {
    std::ios_base::sync_with_stdio(false); // 加速C++ IO
    std::cin.tie(NULL);

    std::string line;
    std::getline(std::cin, line);
    std::pair<int, int> nm = parse_pair(line);
    int n = nm.first; // 市民总数n
    int m = nm.second; // 商店总数m

    if (m == 1) {
        std::cout << 0 << std::endl;
        return 0;
    }

    std::vector<Citizen> all_citizens; // 存储所有市民信息
    // 使用 map 存储每个其他商店的投票者列表
    //键是商店ID,值是Citizen对象的vector
    std::map<int, std::vector<Citizen>> voters_per_other_store; 

    int initial_store1_votes = 0; // 1号店初始票数

    for (int i = 0; i < n; ++i) {
        std::getline(std::cin, line);
        std::pair<int, int> pq = parse_pair(line);
        int p = pq.first; // 商店编号
        int q = pq.second; // 补贴金额
        Citizen citizen = {i, p, q};
        all_citizens.push_back(citizen);

        if (p == 1) {
            initial_store1_votes++;
        } else {
            voters_per_other_store[p].push_back(citizen);
        }
    }

    // 对每个非1号商店的投票者按补贴金额升序排序
    for (auto& pair_val : voters_per_other_store) {
        std::sort(pair_val.second.begin(), pair_val.second.end());
    }

    std::vector<int> current_total_votes(m + 1, 0); // 索引0不用
    for (const auto& c : all_citizens) {
        current_total_votes[c.initial_store]++;
    }

    int max_other_store_initial_votes = 0;
    if (m > 1) {
        for (int j = 2; j <= m; ++j) {
            max_other_store_initial_votes = std::max(max_other_store_initial_votes, current_total_votes[j]);
        }
    }
    
    if (n == 0) { // 题目约束 n >= 1
         std::cout << 0 << std::endl;
         return 0;
    }

    if (current_total_votes[1] > max_other_store_initial_votes && m > 1) {
        std::cout << 0 << std::endl;
        return 0;
    }

    long long min_overall_subsidy = -1; // 用-1表示尚未找到可行方案,或用LLONG_MAX

    for (int target_s1_final_votes = 1; target_s1_final_votes <= n; ++target_s1_final_votes) {
        long long current_subsidy_for_this_target = 0;
        int current_s1_acquired_votes = initial_store1_votes;
        std::set<int> bribed_citizen_ids_in_this_round; // 记录本轮已拉拢市民的ID

        // 阶段1
        for (int store_idx = 2; store_idx <= m; ++store_idx) {
            int current_votes_for_store_idx = 0;
            std::vector<Citizen> potential_bribes_from_this_store;

            if (voters_per_other_store.count(store_idx)) { // 如果该商店有投票者
                const auto& original_voters_of_store = voters_per_other_store.at(store_idx);
                for (const auto& c_original : original_voters_of_store) {
                    if (bribed_citizen_ids_in_this_round.find(c_original.id) == bribed_citizen_ids_in_this_round.end()) {
                        current_votes_for_store_idx++;
                        potential_bribes_from_this_store.push_back(c_original);
                    }
                }
                // potential_bribes_from_this_store 已经是按成本排序的
            }


            int num_to_bribe_mandatorily = current_votes_for_store_idx - (target_s1_final_votes - 1);

            if (num_to_bribe_mandatorily > 0) {
                int bribed_count_from_store = 0;
                for (const auto& citizen_to_bribe : potential_bribes_from_this_store) {
                     if (bribed_count_from_store >= num_to_bribe_mandatorily) break;
                     // 再次检查,虽然理论上已过滤
                     if (bribed_citizen_ids_in_this_round.find(citizen_to_bribe.id) == bribed_citizen_ids_in_this_round.end()) {
                        current_subsidy_for_this_target += citizen_to_bribe.subsidy_cost;
                        current_s1_acquired_votes++;
                        bribed_citizen_ids_in_this_round.insert(citizen_to_bribe.id);
                        bribed_count_from_store++;
                    }
                }
            }
        }

        // 阶段 2
        std::vector<Citizen> available_pool_for_bribing;
        for (const auto& citizen : all_citizens) {
            if (citizen.initial_store != 1 && bribed_citizen_ids_in_this_round.find(citizen.id) == bribed_citizen_ids_in_this_round.end()) {
                available_pool_for_bribing.push_back(citizen);
            }
        }
        std::sort(available_pool_for_bribing.begin(), available_pool_for_bribing.end());

        // 阶段 3
        int additional_votes_needed_for_s1 = target_s1_final_votes - current_s1_acquired_votes;
        if (additional_votes_needed_for_s1 > 0) {
            if (additional_votes_needed_for_s1 > static_cast<int>(available_pool_for_bribing.size())) {
                continue; 
            }
            for (int k = 0; k < additional_votes_needed_for_s1; ++k) {
                const auto& citizen_to_bribe = available_pool_for_bribing[k];
                current_subsidy_for_this_target += citizen_to_bribe.subsidy_cost;
                current_s1_acquired_votes++;
                // bribed_citizen_ids_in_this_round.insert(citizen_to_bribe.id); // 可选,因为是从池中取的
            }
        }

        if (current_s1_acquired_votes >= target_s1_final_votes) {
            bool condition_met = true;
            for (int store_idx_check = 2; store_idx_check <= m; ++store_idx_check) {
                int other_store_final_votes = 0;
                if (voters_per_other_store.count(store_idx_check)) {
                    const auto& original_voters_list = voters_per_other_store.at(store_idx_check);
                    for (const auto& c_original : original_voters_list) {
                        if (bribed_citizen_ids_in_this_round.find(c_original.id) == bribed_citizen_ids_in_this_round.end()) {
                            other_store_final_votes++;
                        }
                    }
                }
                if (other_store_final_votes >= target_s1_final_votes) {
                    condition_met = false;
                    break;
                }
            }
            if (condition_met) {
                if (min_overall_subsidy == -1 || current_subsidy_for_this_target < min_overall_subsidy) {
                    min_overall_subsidy = current_subsidy_for_this_target;
                }
            }
        }
    }
    // 如果从未找到可行方案(例如n=0且未被初始检查捕获),则应输出0
    // 但题目约束 n>=1,所以总能找到方案(最坏情况是把所有人都拉过来)
    std::cout << (min_overall_subsidy == -1 ? 0 : min_overall_subsidy) << std::endl;

    return 0;
}



🏆下一篇:华为OD机试真题 - 简易内存池(Python/JS/C/C++ 2025 B卷 200分)

🏆本文收录于,华为OD机试真题(Python/JS/C/C++)

刷的越多,抽中的概率越大,私信哪吒,备注华为OD,加入华为OD刷题交流群,每一题都有详细的答题思路、详细的代码注释、3个测试用例、为什么这道题采用XX算法、XX算法的适用场景,发现新题目,随时更新。

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

哪 吒

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

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

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

打赏作者

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

抵扣说明:

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

余额充值