B-名牌赌王—集训队

代码取自他人以下仅仅是本人的一些见解:

#include <iostream>
#include <queue>                // 包含小根堆优先队列所需的头文件
#include <unordered_map>        // 包含无序映射所需的头文件
using namespace std;

// 函数:判断是否能构成顺子
bool canFormStraight() {
    int n, m;
    cin >> n >> m;              // 输入牌的总数n和每组顺子的长度m
    priority_queue<int, vector<int>, greater<int>> q;  // 定义小根堆优先队列,用于存储牌的数字,以便后续顺序处理
    unordered_map<int, int> arr;    // 使用无序映射记录每种牌的数量
    while (n--) {               // 循环读取n张牌的数字,并统计每种牌的数量
        int num;
        cin >> num;
        arr[num]++;             // 记录当前数字的数量加1
        q.push(num);            // 将当前数字压入优先队列中,保证从小到大排列
    }
    while (!q.empty()) {        // 循环处理优先队列中的元素,直到队列为空
        int number = q.top();   // 获取队列顶部(最小值)的牌的数字
        q.pop();                // 弹出队列顶部的牌
        if (arr[number] == 0) continue;    // 如果该牌的数量已经为0,则直接跳过当前循环,处理下一张牌
        for (int i = 0; i < m; i++) {      // 遍历每组顺子的长度
            int cnt = arr[number + i]--;   // 获取当前牌及其后续牌的数量,并将当前牌的数量减1
            if (cnt == 0) return false;    // 如果当前牌及其后续牌的数量为0,则无法构成顺子,返回false
        }
    }
    return true;                // 若能顺利构成若干组m长度的顺子,则返回true
}

int main() {
    int t;
    cin >> t;                   // 输入测试用例数量t
    while (t--) {               // 循环处理每个测试用例
        if (canFormStraight()) cout << "YES" << endl;   // 判断是否能构成顺子,如果能,则输出YES
        else cout << "NO" << endl;                     // 如果不能,则输出NO
    }
    return 0;
}
  1. 小根堆优先队列(priority_queue<int, vector<int>, greater<int>>)

    • 小根堆是一种特殊的堆,堆中每个节点的值都小于或等于其子节点的值。在C++中,可以使用 priority_queue 来实现小根堆。
    • 在这个题目中,小根堆优先队列的作用是将牌的数字按从小到大的顺序排列,以便后续按顺序处理。
  2. 无序映射(unordered_map<int, int>)

    • 无序映射是C++中的一种关联容器,它存储键值对,并且可以快速查找指定键对应的值。在无序映射中,键是唯一的,但键值对的存储顺序是不确定的。
    • 在这个题目中,无序映射用于记录每种牌的数量,键是牌的数字,值是该数字对应的牌的数量。
  3. q.push(num) 保证从小到大排列的原理

    • 在C++的 priority_queue 中,如果不指定比较器,默认情况下会使用 less 来比较元素,这会使得优先队列变成大根堆,即根节点的值最大。而我们在声明 priority_queue 时指定了 greater<int> 比较器,这意味着优先队列会按照元素的反序排列,即根节点的值最小。
    • 因此,当我们将牌的数字压入优先队列时,由于使用了 greater<int> 比较器,优先队列会自动按从小到大的顺序排列,这样就保证了牌的数字从小到大的顺序。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值