某餐馆有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
import java.util.*;
public class Restaurant{
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
while(sc.hasNext()){
int n = sc.nextInt(); // n table
int m = sc.nextInt();// m customers
int[] table = new int[n];
for(int i = 0;i < n;i++)
table[i] = sc.nextInt();// volume of a table
int[][] cus = new int[m][2];
for(int j = 0;j < m;j++){
cus[j][0] = sc.nextInt(); // number of customers
cus[j][1] = sc.nextInt(); // money
}
Arrays.sort(table);
Arrays.sort(cus, new Comparator<int[]>(){//通过自定义比较器实现逆序排序
public int compare(int[] a, int[] b){ //老师上课提问过。看到这段代码才明白
return b[1]-a[1]; //三种情况缩写,想起了c语言strcmp1的return (*p1 - *p2); 返回值大于0然后b[1]放在a[1]前面
}
});//这批人只是逆序本身预估值,按预估值来尽可能安排座位实现贪心,而非单人比值,因为一个桌子一批人
long res = 0L;
int index = 0;
boolean[] tableb = new boolean[n];
for(int i = 0;i < m;i++){
if(cus[i][0] > table[n-1])
continue; //如果最大容量桌子都容不下,就执行下次循环
index = bs(table,cus[i][0]);
while(index < n && tableb[index] == true)
index++;//判断标记,一旦桌子有人就往后
if(index < n){
res += cus[i][1];//累计预估资金值
tableb[index] = true;
}
}
System.out.println(res);
}
sc.close();
}
private static int bs(int[] num, int tar){//二分法 查找合适的桌子
int low = 0;
int high = num.length-1;
int mid = 0;
while(low <= high){
mid = (high + low)>>1;//右移操作 除2
if(num[mid] >= tar)
high = mid-1; //能容下就左边再二分查找
else
low = mid+1;//容不下
}
return low;//返回low的下标,尽可能用合适(升序)的容量去容下当前尽可能大(降序)的预估值的一批人
}
}
题 目 有一定 难度,自己没写出来(时间问题),借鉴了的大佬的写法,在这里存下档(个人理解)。希望大佬的解法对有疑惑的小伙伴能提供帮助。