A question of interview from DIDI-BUS

a simple question, but lots of people thought in a complicated way...

Posted by Maizi on 2016-09-15 with time read

滴滴打车的一道android面试题

问题描述如下:

有个一个饭店,有n张桌子,每张桌子可以招待不同数量的客人,且不能拼桌,现在来了m批客人,每批客人有两个属性,一个是客人的总数,一个是他们消费(预计)的总额

请设计一个算法,计算出店家能够获得的最大利润

测试用例:
3 5
2 4 2
1 3
3 5
3 7
5 9
1 10

3 5代表一共有3个桌子 5批客人
2 4 2 代表3张桌子的容量 分别是2 4 2
后面的1 3 代表第一批客人是1个人 消费3元 然后是第二批客人,共3人消费5元
这个测试用例 最后的答案是20

算法描述:


①将客人的数组按照消费降序排列

②将桌子的数组按照桌子容量升序排列

③遍历 中的数组,获取该消费金额的顾客人数,然后遍历 中的数组,若该桌的容量恰好大于或等于顾客人数且没被分配,则将该桌子分配给该批客人且标记该桌已分配,若遍历完 数组也没匹配到符合条件的,则直接放弃服务该批客人.

该问题的很容易将人绕进去,很多人马上想到八皇后问题和其它方向上(如对每批客的人均消费排序什么的),却忽略了它要的是获利最大而不是去服务最多的顾客,该问题其实很简单

最后贴上代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define ARGS_COUNT 15
#define ERROR_PARAMS -1
#define ILLEGAL_PARAMS -2
//排序方式的枚举
enum order {
UP, DOWN
};
/**
* 排序
* or 排序方式
* arr 待排序的二维数组的二级指针
* len 一维数组的长度(依业务设计时一维数组的长度都一样)
*/
void sort(enum order const or, int const ** const arr, int const len) {
while (*(*(arr + 1) + len++) != '\0') {}
if (or == UP) //升序
quickSort(0, len - 2, UP, arr, len);
else //降序
quickSort(0, len - 2, DOWN, arr, len);
}
/**
* 快速排序
* start 待排序的数组的元素的起始位置
* end 待排序的数组的元素的结束位置
* or 排序方式
* arr 待排序的二维数组的二级指针
* len 一维数组的长度(依业务设计时一维数组的长度都一样)
*/
void quickSort(int const start, int const end, enum order const or, int const ** const arr, int const len) {
if (start < end) {
int pivotPos = partition(start, end, or, arr);
quickSort(start, pivotPos - 1, or, arr, len);
quickSort(pivotPos + 1, end, or, arr, len);
}
}
/**
* 快速排序的核心算法--分组(选取轴关键元素,后面的依次与轴关键元素比较,小的放它前面,大的的放它后面)
* low 待分组的数组的元素的起始位置
* high 待分组的数组的元素的结束位置
* or 排序方式
* arr 待排序的二维数组的二级指针
* return 该次分组完成后轴关键元素的位置
*/
int partition(int low, int high, enum order const or, int ** const arr) {
int pivot = *(*arr + low);
int pivotKey = *(*(arr + 1) + low);
int pivotKey_ = *(*(arr + 2) + low);
while (low < high) {
int i;
while (low < high &&
(or == UP ? *(*(arr + 1) + high) >= pivotKey : *(*(arr + 1) + high) <= pivotKey))
--high;
*(*arr + low) = *(*arr + high);
*(*(arr + 1) + low) = *(*(arr + 1) + high);
*(*(arr + 2) + low) = *(*(arr + 2) + high);
while (low < high &&
(or == UP ? *(*(arr + 1) + low) <= pivotKey : *(*(arr + 1) + low) >= pivotKey))
++low;
*(*arr + high) = *(*arr + low);
*(*(arr + 1) + high) = *(*(arr + 1) + low);
*(*(arr + 2) + high) = *(*(arr + 2) + low);
}
*(*arr + low) = pivot;
*(*(arr + 1) + low) = pivotKey;
*(*(arr + 2) + low) = pivotKey_;
return low;
}
/**
* 校验输入参数,并将其转换成整形数组
* argvArr 转换后的整形数组
* argv 程序输入参数的字符串
* return 数据校验的结果,如果出错则返回-2,成功则返回0
*/
int checkArgs(int *const argvArr, char const * const argv) {
size_t len = strlen(argv);
int i;
char buf[32] = {};
char index = 0;
int count = 0;
for (i = 0; i < len; i++) {
char tmp = argv[i];
if (tmp == ',') {//截数字
*(buf+count) = '\0';
*(argvArr+index++) = atoi(buf);
count = 0;
} else if (tmp > 47 && tmp < 58) {
*(buf+count++) = tmp;
continue;
} else//非法字符
return ILLEGAL_PARAMS;
}
*(buf+count) = '\0';
*(argvArr+index++) = atoi(buf);
return 0;
}
/**
* 初始化各数据结构
* arr 待初始化的二维数组的二级指针
* count 该二维数组的一维数组的长度
* index 初始化动作所需输入(一维整形数组)的起始索引位置
* delta 初始化动作所需输入(一维整形数组)两个元素之间的偏移量
* params 初始化动作所需输入(一维整形数组)
* flag 是否需要初始化二维数组的第二位的第三个一维数组
*/
void init(int **const arr, int const count, int const index, int const delta, int const * const params, char const flag) {
int i;
for (i = 0; i < count; ++i) {
*(*arr + i) = i + 1;
*(*(arr + 1) + i) = *(params + index + i * delta);
if (flag)
*(*(arr + 2) + i) = *(params + index - 1 + i * delta);
}
}
/**
* 调度算法
* tableNo 桌子相关信息的二维数组的二级指针
* taNo 桌子的数量
* teamNo 客人组相关信息的二维数组的二级指针
* teNo 客户组的数量
* return 当前最大盈利额
*/
int schedule(int **const tableNo, int const taNo, int **const teamNo, int const teNo) {
int i;
int profit = 0;
for (i = 0; i < teNo; ++i) {
int curTeamNo = *(*teamNo + i);
int curTeamPay = *(*(teamNo + 1) + i);//当前该批客人的总消费
int curTeamLen = *(*(teamNo + 2) + i);//当前该批客人的人数
int j;
for (j = 0; j < taNo; ++j) {
if (*(*(tableNo + 2) + j) == 0 && *(*(tableNo + 1) + j) >= curTeamLen) {
*(*(tableNo + 2) + j) = i + 1;//记录该桌服务的客人的teamNo角标+1
profit += curTeamPay;
break;
}//else{} 如果找不到能容纳该批客人的桌子,那就直接放弃服务该批客人
}
}
return profit;
}
int main(int args, char **argv) {
if (args != 2) {
perror("please input the params with ',' spliting. ");
return ERROR_PARAMS;
}
int arr[ARGS_COUNT];
if (checkArgs(arr, *(argv + 1)) < 0) {
perror("please check your params with character of NaN. ");
return ILLEGAL_PARAMS;
}
int i;
int *tableNo[3];//[桌子编号,桌子容量,该批客人在数组中的序列号]
*tableNo = (int *) malloc(arr[0] * sizeof(int));
*(tableNo + 1) = (int *) malloc(arr[0] * sizeof(int));
*(tableNo + 2) = (int *) calloc(arr[0], sizeof(int));
int *teamNo[3];//[客人批号,该批客人总消费,该批客人人数]
*teamNo = (int *) malloc(arr[0] * sizeof(int));
*(teamNo + 1) = (int *) malloc(arr[0] * sizeof(int));
*(teamNo + 2) = (int *) malloc(arr[0] * sizeof(int));
init(tableNo, arr[0], 2, 1, arr, 0);
init(teamNo, arr[1], 6, 2, arr, 1);
sort(UP, tableNo, arr[0]);
sort(DOWN, teamNo, arr[1]);
int ret = schedule(tableNo, arr[0], teamNo, arr[1]);
printf("max profit : %d\nscheduling plan:\n", ret);
for (i = 0; i < arr[0]; ++i) {
if (*(*(tableNo + 2) + i) != 0) {
int index = *(*(tableNo + 2) + i);
printf("table %d is disbursed to team %d with %d people and %d payment.\n",
*(*tableNo + i),
*(*teamNo + index - 1),
*(*(teamNo + 2) + index - 1),
*(*(teamNo + 1) + index - 1));
}
}
//释放资源
for (i = 0; i < arr[0]; ++i) {
free(*(tableNo + i));
free(*(teamNo + i));
}
return 0;
}

附上测试结果:

1
2
3
4
5
6
/home/maizi/.CLion2016.2/system/cmake/generated/Demo-71a0270b/71a0270b/Debug/Demo 3,5,2,4,2,1,3,3,5,3,7,5,9,1,10
max profit : 20
scheduling plan:
table 1 is disbursed to team 5 with 1 people and 10 payment.
table 3 is disbursed to team 1 with 1 people and 3 payment.
table 2 is disbursed to team 3 with 3 people and 7 payment.


2016-09-15
— Maizi