作者的话:若有朋友复制代码去PAT试着运行遇到问题的:
1.可能是格式问题,可以先把从本站复制的代码粘贴到记事本,再把记事本里的代码复制,然后粘贴到PAT的代码区,提交本题回答,应该就可以了;
2.可能是注释原因,PAT有时候检测到注释会编译错误,所以可以先把注释删了,再进行提交回答;
3.可能是作者当初根据题目写出来的代码仍存在一些疏漏,而恰好当时的测试机制没那么完善,没检测出问题。后面测试机制有所更新,故出现问题,若有相关需要的可以评论区留言或私信作者,我看到的话会去再查一下疏漏之处,然后更新文章。
一、题目描述
月饼是中国人在中秋佳节时吃的一种传统食品,不同地区有许多不同风味的月饼。现给定所有种类月饼的库存量、总售价、以及市场的最大需求量,请你计算可以获得的最大收益是多少。
注意:销售时允许取出一部分库存。样例给出的情形是这样的:假如我们有 3 种月饼,其库存量分别为 18、15、10 万吨,总售价分别为 75、72、45 亿元。如果市场的最大需求量只有 20 万吨,那么我们最大收益策略应该是卖出全部 15 万吨第 2 种月饼、以及 5 万吨第 3 种月饼,获得 72 + 45/2 = 94.5(亿元)。
输入格式:
每个输入包含一个测试用例。每个测试用例先给出一个不超过 1000 的正整数 N表示月饼的种类数、以及不超过 500(以万吨为单位)的正整数 D 表示市场最大需求量。随后一行给出 N 个正数表示每种月饼的库存量(以万吨为单位);最后一行给出 N 个正数表示每种月饼的总售价(以亿元为单位)。数字间以空格分隔。
输出格式:
对每组测试用例,在一行中输出最大收益,以亿元为单位并精确到小数点后 2 位。
输入样例:
3 20
18 15 10
75 72 45
输出样例:
94.50
二、解题思路
读题:
//客串月饼卖家
//第一行输入月饼的种类(为整数)和月饼的市场需求量(为整数)
//第二行输入每种月饼的库存量(正数)
//第三行输入每种月饼全部卖掉分别能得到的钱(正数)
//月饼种类N<=1000,市场需求量D<=500
//要求程序输出最大收益,精确到小数点后2位
思路:
1.定义需要的变量,按要求一行一行接收数据;
2.设置循环将所有的月饼按单价降序排列,后面卖月饼时先卖价格高的(特别注意:单价要特别存储在新的数组中,不能丢失原来的总售价,因为单价是总售价除以存货,是两个浮点数相除得到的浮点数,可能超过浮点数的精度,除法也可能除不尽,最后得到的单价乘以存货不一定还是原来的总售价,当市场需求量>月饼存货,此时要用到某种月饼的总售价,所以每种月饼的总售价要保留);
3.设置外层循环,内部嵌套判断语句。外层循环每一轮循环做一次判断,若此时单价最高(即能优先卖掉能带来最大收益)的月饼存货>=需求量,则只卖这一种月饼,需求量是多少,就卖多少(这时候因为无法卖光,所以要用到单价,数据损失是可以接受的,也是不能避免的),即最大收益=最高月饼单价*市场需求量;如果市场需求量较大,则单价最高月饼优先卖光,此时市场需求量要减去单价最高月饼的存货,之后第二轮循环再卖单价第二高的月饼,再进行市场需求量和单种月饼存货的比较,根据结果执行不同的分支,以此类推;
4.以保留两位的浮点数格式输出最大收益。(为什么输出函数不放在前面,因为有种特殊情况是所有月饼的存货加起来也达不到市场需求量,所以要等到循环跳出或者循环正常结束,即市场饱和或存货全部卖光了,才知道最大收益,这时候才能输出最大收益)。
三、具体实现
0.标准C源程序框架
#include <stdio.h>
int main()
{
return 0;
}
1.定义需要的变量,按要求一行一行接收数据,并计算每种月饼的单价;
int n;//市场需求量
double d = 0.0;//因为市场需求量后面可能要和浮点数相减,并且还要继续保存结果,为避免损失数据,故用浮点型
double store[1000];//每种月饼的存货
double total_price[1000];//每种月饼的总售价
double single_price[1000];//每种月饼的单价
int i = 0, j = 0;//因为后面用了冒泡排序,所以设置两个循环变量
double temp = 0.0, max = 0.0;//temp用于交换,max用于存储最大收益
//第一行输入月饼的种类(为整数)和月饼的市场需求量(为整数)
scanf("%d %lf", &n, &d);
//第二行输入每种月饼的库存量(正数)
while (i < n) { scanf("%lf", &store[i++]); }
i = 0;
//第三行输入每种月饼全部卖掉分别能得到的钱(正数),并计算每种月饼的单价,方便后面优先卖收益高的月饼
while (i < n)
{
scanf("%lf", &total_price[i]);
single_price[i] = total_price[i] / store[i];
i++;
}
2.设置循环将所有的月饼按单价降序排列,后面卖月饼时先卖价格高的(特别注意:单价要特别存储在新的数组中,不能丢失原来的总售价,因为单价是总售价除以存货,即两个浮点数相除得到的浮点数,可能超过浮点数的精度,除法也可能除不尽,最后得到的单价乘以存货不一定还是原来的总售价,当市场需求量>月饼存货,此时要用到某种月饼的总售价,所以每种月饼的总售价要保留);
//把数组按单价降序排列
for (i = 0; i < n - 1; i++)
{
for (j = 0; j < n - 1 - i; j++)
{
if (single_price[j] < single_price[j + 1])
{
temp = single_price[j];
single_price[j] = single_price[j + 1];
single_price[j + 1] = temp;
temp = total_price[j];
total_price[j] = total_price[j + 1];
total_price[j + 1] = temp;
temp = store[j];
store[j] = store[j + 1];
store[j + 1] = temp;
}
}
}
3.设置外层循环,内部嵌套判断语句。外层循环每一轮循环做一次判断,若此时单价最高(即能优先卖掉能带来最大收益)的月饼存货>=需求量,则只卖这一种月饼,需求量是多少,就卖多少(这时候因为无法卖光,所以要用到单价,精度损失是可以接受的),即最大收益=最高月饼单价*市场需求量;如果市场需求量较大,则单价最高月饼优先卖光,此时市场需求量要减去单价最高月饼的存货,之后第二轮循环再卖单价第二高的月饼,再进行市场需求量和单种月饼存货的比较,根据结果执行不同的分支,以此类推;
i = 0;
while (i < n)
{
if (store[i] >= d)//当前种类月饼存货大于剩下需求的话,他还要多少,那就卖多少,收益加上之前可能已经卖过的其他种类月饼的收益就是总的最大收益
{
max += single_price[i] * d;
break;
}
else//当前种类月饼满足不了市场需求的话,先全部卖光,累计收益,新一轮循环再去卖别的月饼
{
max += total_price[i];
d -= store[i];
i++;
}
}
4.以保留两位的浮点数格式输出最大收益。(为什么输出函数不放在前面,因为有种特殊情况是所有月饼的存货加起来也达不到市场需求量,所以要等到循环跳出或者循环正常结束,即市场饱和或存货全部卖光了,才知道最大收益,这时候才能输出最大收益)。
printf("%.2lf", max);//打印,别忘了保留两位小数哦
四、测试数据
没有确切的测试数据,因为存货、总价都有可能是小数,你要考虑这种情况;
同时由于存货是小数,当单价最高月饼的存货小于市场需求量的时候,市场需求量需要减去存货,在这之后市场需求量也可能变成小数,你也要考虑这种情况;
因为总价/存货的结果可能小数点后会有很多位,也可能根本除不尽,会损失一部分收益,单价实际上*存货无法再得到原来的总售价了,这种情况也要考虑。
五、全部代码
#include <stdio.h>
int main()
{
int n;//市场需求量
double d = 0.0;//因为市场需求量后面可能要和浮点数相减,并且还要继续保存结果,为避免损失数据,故用浮点型
double store[1000];//每种月饼的存货
double total_price[1000];//每种月饼的总售价
double single_price[1000];//每种月饼的单价
int i = 0, j = 0;//因为后面用了冒泡排序,所以设置两个循环变量
double temp = 0.0, max = 0.0;//temp用于交换,max用于存储最大收益
//第一行输入月饼的种类(为整数)和月饼的市场需求量(为整数)
scanf("%d %lf", &n, &d);
//第二行输入每种月饼的库存量(正数)
while (i < n) { scanf("%lf", &store[i++]); }
i = 0;
//第三行输入每种月饼全部卖掉分别能得到的钱(正数),并计算每种月饼的单价,方便后面优先卖收益高的月饼
while (i < n)
{
scanf("%lf", &total_price[i]);
single_price[i] = total_price[i] / store[i];
i++;
}
//把数组按单价降序排列
for (i = 0; i < n - 1; i++)
{
for (j = 0; j < n - 1 - i; j++)
{
if (single_price[j] < single_price[j + 1])
{
temp = single_price[j];
single_price[j] = single_price[j + 1];
single_price[j + 1] = temp;
temp = total_price[j];
total_price[j] = total_price[j + 1];
total_price[j + 1] = temp;
temp = store[j];
store[j] = store[j + 1];
store[j + 1] = temp;
}
}
}
i = 0;
while (i < n)
{
if (store[i] >= d)//当前种类月饼存货大于剩下需求的话,他还要多少,那就卖多少,收益加上之前可能已经卖过的其他种类月饼的收益就是总的最大收益
{
max += single_price[i] * d;
break;
}
else//当前种类月饼满足不了市场需求的话,先全部卖光,累计收益,新一轮循环再去卖别的月饼
{
max += total_price[i];
d -= store[i];
i++;
}
}
printf("%.2lf", max);//打印,别忘了保留两位小数哦
return 0;
}
六、优化代码
优化方向挺多的,冒泡排序可以设置判断,当循环排了几个数后可能顺序已经是对的了,但循环次数还有,可以设置判断提前结束,减少不必要的时间消耗;
也可以直接用qsort()函数减少代码量和时间复杂度。