目录
题目链接:4.食堂 - 蓝桥云课
注:下述题目描述和示例均来自蓝桥云客
题目描述
S 学校里一共有 a2 个两人寝、a3 个三人寝,a4 个四人寝,而食堂里有 b4 个四人桌和 b6 个六人桌。学校想要安排学生们在食堂用餐,并且满足每个寝室里的同学都在同一桌就坐,请问这个食堂最多同时满足多少同学用餐?
输入格式
采用多组数据输入。
输入共 q+1 行。
第一行为一个正整数 q 表示数据组数。
后面 q 行,每行五个非负整数 a2,a3,a4,b4,b6 表示一组数据。
输出格式
输出共 q 行,每行一个整数表示对应输入数据的答案。
样例输入
2
3 0 1 0 1
0 2 2 1 1
样例输出
6
10
样例说明
对于第一组数据,只有一个六人桌,因此最多安排三个两人寝的同学就餐,答案为 (2+2+2)=6 。
对于第二组数据,用一个六人桌安排两个三人寝的同学,用一个四人桌安排一个四人寝的同学,答案为 (3+3)+(4)=10( 。
评测用例规模与约定
对于 20%20% 的评测用例,保证 a2+a3+a4≤8 。
对于 100%100% 的评测用例,保证 q≤100,b4+b6≤a2+a3+a4≤100。
解法一:贪心,能解决的好方法
比赛时候我的答案
import java.util.Scanner;
public class DiningArrangementFixed {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int q = scanner.nextInt();
while(q-- > 0){
int a2 = scanner.nextInt();
int a3 = scanner.nextInt();
int a4 = scanner.nextInt();
int b4 = scanner.nextInt();
int b6 = scanner.nextInt();
int res = 0;
// 1.先看3+3的
while(a3 >= 2 && b6 >= 1){
a3 -= 2;
b6--;
res += 6;
}
// 2.看4+2的
while(a4 >= 1 && a2 >= 1 && b6 >= 1){
a4--;
b6--;
res += 6;
}
// 3.看单独一个4的
while(a4 >= 1 && b4 >= 1){
a4--;
b4--;
res += 4;
}
// 4.看2+2+2的
while(a2 >= 3 && b6 >= 1){
a2 -= 3;
b6--;
res += 6;
}
// 5.看2+2的
while(a2 >= 2 && b4 >= 1){
a2 -= 2;
b4--;
res += 4;
}
// -------------上述都是满配的情况-------------
// -------------下面展示不满配的情况-------------
// 1.看b6放3+2的
while(a3 >= 1 && a2 >= 1 && b6 >= 1){
a3--;
a2--;
b6--;
res += 5;
}
// 5.看b4放3的
while(a3 >= 1 && b4 >= 1){
a3--;
b4--;
res += 3;
}
// 2.看b6放4的
while(a4 >= 1 && b6 >= 1){
a4--;
b6--;
res += 4;
}
// 3.看b6放3的
while(a3 >= 1 && b6 >= 1){
a3--;
b6--;
res += 3;
}
// 4.看b6放2的
while(a2 >= 1 && b6 >= 1){
a2--;
b6--;
res += 2;
}
// 5.看b4放2的
while(a2 >= 1 && b4 >= 1){
a2--;
b4--;
res += 2;
}
System.out.println(res);
}
scanner.close();
}
}
最后的效果也不是很好但是也是拿到一点分数
于是我就思考我到底哪里错了。(最后发现是个很小的错误┭┮﹏┭┮)
我重新想了想,我们的大体思路没有改变,还是先满配,再放空余的。
方法思路
-
处理四人桌:优先安排四人寝,然后是两个两人寝的组合,接着是三人寝,最后是单人两人寝。
-
处理六人桌:优先安排两个三人寝,然后是四人寝和两人寝的组合,接着是三个两人寝,之后是四人寝,然后是三人寝和两人寝的组合,最后处理剩余的两人寝和三人寝。
其实中间有很多的顺序都是可以换的,但是2+2+2一定要在2+2之前
Java写法:
import java.util.Scanner;
public class DiningArrangementFixed {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int q = scanner.nextInt();
while(q-- > 0){
int a2 = scanner.nextInt();
int a3 = scanner.nextInt();
int a4 = scanner.nextInt();
int b4 = scanner.nextInt();
int b6 = scanner.nextInt();
int res = 0;
// 1.先看3+3的
while(a3 >= 2 && b6 >= 1){
a3 -= 2;
b6--;
res += 6;
}
// 2.看4+2的
while(a4 >= 1 && a2 >= 1 && b6 >= 1){
a4--;
a2--;
b6--;
res += 6;
}
// 3.看单独一个4的
while(a4 >= 1 && b4 >= 1){
a4--;
b4--;
res += 4;
}
// 4.看2+2+2的
while(a2 >= 3 && b6 >= 1){
a2 -= 3;
b6--;
res += 6;
}
// 5.看2+2的
while(a2 >= 2 && b4 >= 1){
a2 -= 2;
b4--;
res += 4;
}
// -------------上述都是满配的情况-------------
// -------------下面展示不满配的情况-------------
// 1.看b6放3+2的
while(a3 >= 1 && a2 >= 1 && b6 >= 1){
a3--;
a2--;
b6--;
res += 5;
}
// 5.看b4放3的
while(a3 >= 1 && b4 >= 1){
a3--;
b4--;
res += 3;
}
// 2.看b6放4的
while(a4 >= 1 && b6 >= 1){
a4--;
b6--;
res += 4;
}
// 3.看b6放3的
while(a3 >= 1 && b6 >= 1){
a3--;
b6--;
res += 3;
}
// 4.看b6放2的
while(a2 >= 1 && b6 >= 1){
a2--;
b6--;
res += 2;
}
// 5.看b4放2的
while(a2 >= 1 && b4 >= 1){
a2--;
b4--;
res += 2;
}
System.out.println(res);
}
scanner.close();
}
}
C++写法:
#include <iostream>
int main() {
int q;
std::cin >> q;
while(q-- > 0) {
int a2, a3, a4, b4, b6;
std::cin >> a2 >> a3 >> a4 >> b4 >> b6;
int res = 0;
// 1. 先看3+3的
while(a3 >= 2 && b6 >= 1) {
a3 -= 2;
--b6;
res += 6;
}
// 2. 看4+2的
while(a4 >= 1 && a2 >= 1 && b6 >= 1) {
--a4;
--a2;
--b6;
res += 6;
}
// 3. 看单独一个4的
while(a4 >= 1 && b4 >= 1) {
--a4;
--b4;
res += 4;
}
// 4. 看2+2+2的
while(a2 >= 3 && b6 >= 1) {
a2 -= 3;
--b6;
res += 6;
}
// 5. 看2+2的
while(a2 >= 2 && b4 >= 1) {
a2 -= 2;
--b4;
res += 4;
}
// -------------上述都是满配的情况-------------
// -------------下面展示不满配的情况-------------
// 1. 看b6放3+2的
while(a3 >= 1 && a2 >= 1 && b6 >= 1) {
--a3;
--a2;
--b6;
res += 5;
}
// 2. 看b4放3的
while(a3 >= 1 && b4 >= 1) {
--a3;
--b4;
res += 3;
}
// 3. 看b6放4的
while(a4 >= 1 && b6 >= 1) {
--a4;
--b6;
res += 4;
}
// 4. 看b6放3的
while(a3 >= 1 && b6 >= 1) {
--a3;
--b6;
res += 3;
}
// 5. 看b6放2的
while(a2 >= 1 && b6 >= 1) {
--a2;
--b6;
res += 2;
}
// 6. 看b4放2的
while(a2 >= 1 && b4 >= 1) {
--a2;
--b4;
res += 2;
}
std::cout << res << std::endl;
}
return 0;
}
AC情况
时间复杂度和空间复杂度
该算法的时间复杂度主要取决于输入数据的规模以及内部循环执行的次数。对于每个测试用例(由外部while(q-- > 0)
循环控制),算法通过一系列的while
循环来计算结果。这些内部循环的执行次数依赖于输入值a2
, a3
, a4
, b4
, 和 b6
。
- 每个内部
while
循环最多执行次数与对应变量的初始值成正比。例如,处理a3 >= 2 && b6 >= 1
条件的循环最多执行min(a3/2, b6)
次。 - 因为每次循环都会减少至少一个相关变量的数量,并且这些变量的总数量是有限的(即它们的初始值),所以可以认为每个内部循环在最坏情况下的时间复杂度与这些变量的最大值成线性关系。
因此,对于每个单独的测试用例,算法的时间复杂度大致为O(n),其中n是所有输入参数(a2
, a3
, a4
, b4
, b6
)最大值的一个函数。如果考虑q个测试用例的整体影响,则总时间复杂度为O(q * n)。
空间复杂度分析
空间复杂度主要关注算法运行过程中所需的额外存储空间。在这个程序中:
- 只使用了几个整型变量(
a2
,a3
,a4
,b4
,b6
,res
)来存储输入和中间结果。 - 不论输入大小如何,使用的额外空间量保持不变。
因此,该算法的空间复杂度为O(1),即常数级别的空间复杂度。这意味着它不需要随输入大小增加而增加额外的内存空间,除了用于接收输入的那些固定数量的变量之外。
总结:此算法具有线性时间复杂度O(q * n)和常数空间复杂度O(1),这里的n指的是单个测试用例中输入参数的最大值。这种特性使得该算法非常适合处理相对较小规模的输入数据集。
总结
我怎么说呢,这个贪心其实是一个很简单的题目,但是临场发挥的时候就是发挥不出来,我真的服了铁铁。好像我只会暴力求解。┭┮﹏┭┮