餐馆问题

题目描述

某餐馆有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范围内。

解题关键:

本题有点像贪心算法,关键的问题在于如何快速匹配合适的桌子给当前这一波的客人,可以对桌子按从小到大的顺序排序,然后遍历的方法查找合适的桌子,但这种方法会大大增加程序的时间复杂度;较快的方法就是采用二分法查找这样程序的时间复杂度会小的多。

import java.util.*;

/**
 * 主方法
 */
public class Main {
    public static void main(String[] args) {
        Scanner input =new Scanner(System.in);
        //输入n , m
        int n = input.nextInt();
        int m = input.nextInt();
        //输入n张桌子的容纳量
        long[] desks = new long[n];
        for(int i = 0; i<n; i++) {
            desks[i] = input.nextLong();
        }
        Arrays.sort(desks);
        //输入m波客人
        Customer[] customers = new Customer[m];
        for(int i = 0; i<m; i++){
            customers[i] = new Customer(input.nextLong(),input.nextLong());
        }
        //对客人按消费金额从大小排序
        Arrays.sort(customers,new Comparator(){
            @Override
            public int compare(Object o1, Object o2) {

                if(((Customer) o1).getMonetary()>((Customer) o2).getMonetary()) {
                    return -1;
                } else if(((Customer) o1).getMonetary()<((Customer) o2).getMonetary()) {
                    return 1;
                }else {
                    return 0;
                }
            }
        });

        boolean[] desks_use = new boolean[n];
        long sum = 0;
        //依次取出客人,如果有合适的桌子就安排客人入座
        for(int i=0;i<m; i++){
            int index = bs(desks,customers[i].getTotle());
            while (index < n && desks_use[index] ==true ){
                index ++;
            }
            if(index<n){
                sum+=customers[i].getMonetary();
                desks_use[index] = true;
            }
        }
        System.out.println(sum);
    }

    //二分法找到合适的桌子
    static int bs(long[] desks, Long tar){
        int low=0;
        int high=desks.length-1;
        int mid;
        while(low <= high){
            mid=(high+low)>>1;
            if(desks[mid]>=tar)
                high=mid-1;
            else
                low=mid+1;
        }
        return low;
}
}

/**
 * 顾客类
 */
class Customer{
    private Long totle;
    private Long monetary;

    public Customer(Long totle, Long monetary) {
        this.totle = totle;
        this.monetary = monetary;
    }

    public Long getTotle() {
        return totle;
    }

    public Long getMonetary() {
        return monetary;
    }

    public void setTotle(Long totle) {
        this.totle = totle;
    }

    public void setMonetary(Long monetary) {
        this.monetary = monetary;
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值