笔试专题,牛客网,餐馆

本文介绍了一种餐馆在有限桌子数量下,通过合理安排不同批次顾客以达到最大经济效益的算法。该算法首先对顾客按消费额度降序排列,并对桌子按容纳人数降序排列。然后逐一尝试安排消费最高的顾客群,确保不超出桌子容纳限制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

链接: https://www.nowcoder.com/questionTerminal/d2cced737eb54a3aa550f53bb3cc19d0
来源:牛客网

某餐馆有n张桌子,每张桌子有一个参数:a 可容纳的最大人数; 有m批客人,每批客人有两个参数:b人数,c预计消费金额。 在不允许拼桌的情况下,请实现一个算法选择其中一部分客人,使得总预计消费金额最大
输入描述:
输入包括m+2行。 第一行两个整数n(1 <= n <= 50000),m(1 <= m <= 50000) 第二行为n个参数a,即每个桌子可容纳的最大人数,以空格分隔,范围均在32位int范围内。 接下来m行,每行两个参数b,c。分别表示第i批客人的人数和预计消费金额,以空格分隔,范围均在32位int范围内。


输出描述:
输出一个整数,表示最大的总预计消费金额
示例1

输入

3 5 2 4 2 1 3 3 5 3 7 5 9 1 10

输出

20

题意简单理解,这些顾客分为几批,但都是一起来的,他们每一批都不想分开坐,所以要把这几批人都分别安排在一个桌子上,但是为了谋求最大的经济效益,来的人有多有少,分给他们的桌子就要从人数来判断。比如有一批人来,把他们呢从带来的钱来排序比较,钱最多要优先分配,因为桌子就那几张桌子,每个桌子带来的收益最高,那么整体的收益就是最大的,前提条件是不能拼桌,所以当我们看到带最多的钱的人来时,我么就从桌子容量数目最少的(桌子是升序的)开始寻找能够容纳人数的桌子,如果这队人数少于最大容纳量,那么就把这些钱记录下来,收录这些人,接下来再寻找下一队带钱最多的人。


方法1.

链接:https://www.nowcoder.com/questionTerminal/d2cced737eb54a3aa550f53bb3cc19d0
来源:牛客网


/*
思路:优先选消费额度大的客人安排就餐
对客人按照消费额度排序(大->小)
对桌子按照容量排序(大->小)
选取当前消费额度最大客人:
1.如果没有桌子可用,结束;
2.如果人数过多无法安排,跳过;
3.如果可安排,则找到最合适的桌位,可就餐的桌位中容量最小的;
   3.1向这批客人收费;
   3.2将桌子从可用资源中删除;
直到没有桌子可用或所有客人全部安排
*/
#include<iostream>
#include<vector>
#include<map>
#include<algorithm>
using namespace std;
int main()
{
    int n, m, b, c;
    int num;
    vector< int > desk; //可用桌子资源的容量
    vector<pair< int , int >> customer; //预计消费,人数
    cin >> n >> m;
    while (n--) //输入桌子容量
    {
        cin >> num;
        desk.push_back(num);
    }
    //对桌子容量从大到小排序
    sort(desk.begin(), desk.end());
    reverse(desk.begin(), desk.end());
    vector< bool > flag(desk.size(), false );
    while (m--)
    {
        cin >> b >> c;
        customer.push_back(make_pair(c, b));
    }
    //对顾客按消费额度从大到小排序
    sort(customer.begin(), customer.end());
    reverse(customer.begin(), customer.end());
     
    long long ret = 0; //必须是long long,int会溢出
    for ( int it = 0; it < customer.size(); ++it)
    {
        if (desk.size() == 0) //没有可用的桌子了
            break ;
        int consumeMoney = customer[it].first;
        int countOfPeople = customer[it].second;
        if (desk[0] < countOfPeople) //最大的桌子也容不下这批客人
            continue ;
        int i = 0;
        while (i < desk.size() && desk[i] >= countOfPeople) //找到可以容纳这批客人的最小桌子
            ++i; //i为第一个不可容纳的桌子,则i-1位这批客人的最佳桌位
        ret = ret + consumeMoney; //收入增加
        desk.erase(desk.begin() + i - 1); //桌子从可用资源中删除
    }
    cout << ret << endl;
}

方法2

链接:https://www.nowcoder.com/questionTerminal/d2cced737eb54a3aa550f53bb3cc19d0

来源:牛客网

这个使用multiset特点来进行使用的,用low_bound直接来寻找第一个大于等于val值的下标


#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <set>
 
struct guest {
     int num;
     int money;
};
bool cmp(guest a, guest b) {
     if (a.money == b.money) {
         return a.num < b.num;
     }
     return a.money > b.money;
}
int main() {
     using namespace std;
     int n, m;
     while (cin >> n >> m) {
         multiset< int > desk;
         vector<guest> people(m);
         long long ans = 0 ;
         for ( int i = 0 ; i < n; i++) {
             int temp;
             cin >> temp;
             desk.insert(temp);
         }
         for ( int i = 0 ; i < m; i++) {
             int a, b;
             cin >> a >> b;
             people[i].num = a;
             people[i].money = b;
         }
         sort(people.begin(), people.end(), cmp);
         for ( int i = 0 ; i < m; i++) {
             if (desk.empty()) {
                 break ;
             }
             if (people[i].num <= *desk.rbegin()) {
                 ans += people[i].money;
                 desk.erase(desk.lower_bound(people[i].num));
             }
         }
         cout << ans << endl;
     }
     return 0 ;
}

方法3

另一种方法是利用了优先序列的方法,自动对数据集从大到小排序,在查找方面可以使用二分法

链接:https://www.nowcoder.com/questionTerminal/d2cced737eb54a3aa550f53bb3cc19d0
来源:牛客网

include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
using namespace std;
 
struct custom {
     int num;
     int cost;
};
class queue_cmp {
public :
     bool operator()(custom a, custom b) {
         return a.cost < b.cost;
     }
};
bool sort_cmp(custom a, custom b) {
     return a.num < b.num;
}
int main() {
     int n, m;
     cin >> n >> m;
     vector< int > tables(n);
     vector<custom> customs(m);
     for ( int i = 0; i < n; i++)
         cin >> tables[i];
     for ( int i = 0; i < m; i++)
         cin >> customs[i].num >> customs[i].cost;
     sort(tables.begin(), tables.end());
     sort(customs.begin(), customs.end(),sort_cmp);
     priority_queue<custom, vector<custom>, queue_cmp> que;
     long long sum = 0;
     int j = 0;
     for ( int i = 0; i < n; i++) {
         for (; j < m && customs[j].num <= tables[i]; j++)
             que.push(customs[j]);
         if (que.empty()) continue ;
         sum += que.top().cost;
         que.pop();
     }
     cout << sum << endl;
     return 0;
}

fa
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值