写在前面:
题解是对具体题目的编程实现,不会具体讲解C语言语法。请先大致学习好语法,自己敲敲代码后再看题解(上来就直接看题解的习惯不好哟~)。在每一题的题解之前,会列出本题涉及到的语法知识供参考,可以在教材或其他学习资源找到这些内容学习。😀
本题的预备知识:
- 变量的定义与赋值操作
- 输入(scanf)输出(printf)语句
- for循环语句及其嵌套
- 循环体内break语句的使用
马戏团观众人数
| 成绩 | 10 | 开启时间 | 2020年03月21日 星期六 08:00 |
| 折扣 | 0.8 | 折扣时间 | 2020年04月18日 星期六 23:00 |
| 允许迟交 | 否 | 关闭时间 | 2020年05月28日 星期四 23:00 |
一个马戏团表演, n 个座位全满,全部门票收入是 120 元,现在知道,男人每人 5 元,女人每人 2 元,小孩每人 1 角。编程,输入总人数 n ,输出满足要求的男人、女人和小孩人数的全部方案。若 n 人无法满足条件,则输出“No output\n”。
输入: 人数 n
输出: 男人、女人和小孩人数
| 测试输入 | 期待的输出 | 时间限制 | 内存限制 | 额外进程 | |
|---|---|---|---|---|---|
| 测试用例 1 |
|
| 1秒 | 64M | 0 |
题解
本题可以直接枚举三种人的人数,找到在该人数条件下满足收入为120的情况。但是考虑到女人、小孩、男人的总人数规定为n,故枚举之间有一定的关联,需要先理清楚枚举的一般规律。
通过审题:小孩的门票为 1毛,而总的收入为120是一个整数,则说明小孩人数必须是0或10的倍数。根据其特殊性,故我们将小孩的枚举放在最外层(先枚举小孩),然后在依次枚举男人、女人。在枚举时,一定要保证三种人的数量和为n,否则为无效枚举。
其中还需要一个flag来标记是否有找到合适的答案,一旦找到我们就将其赋值为1,那么在结束循环后,我们通过flag的值是否改动为1就能判断出我们在枚举期间是否有找到合适的答案。
#include <stdio.h> //导入stdio.h库,里面包含输入输出函数
int main() {
int n; //定义一个整型变量,用于存储总人数
scanf("%d", &n); //处理输入
int num_of_kid, num_of_woman, num_of_man; //分别存储小孩、女人、男人的人数
int money_kid, money_woman, money_man; //分别存储小孩、女人、男人的门票钱
int flag = 0; //若flag = 1则表示有答案输出,否则没有
/* 循环考虑每一种情况 */
for (num_of_kid = 0; num_of_kid <= n; num_of_kid += 10) {
money_kid = num_of_kid * 0.1; //计算小孩的门票钱
for (num_of_man = 0; num_of_man <= n - num_of_kid; num_of_man++) {
num_of_woman = n - num_of_kid - num_of_man;
money_woman = num_of_woman * 2; //计算女人的门票钱
money_man = num_of_man * 5; //计算男人的门票钱
/* 判断该情况下是否满足条件 */
if (money_kid + money_woman + money_man == 120) {
flag = 1; //标记有输出
printf("%d,%d,%d\n", num_of_man, num_of_woman, num_of_kid); //输出结果
}
}
}
if (flag == 0) //若一直没有输出
printf("No output\n");
}
注意:
money_kid = num_of_kid * 0.1 这条语句语句是将表达式计算的结果赋值给 money_kid(int型)。表达式中 num_of_kid 是整型,0.1 是浮点型。故计算结果会是浮点型(编译器会选取表达式中类型最精确的,作为表达式的结果类型,以防止数据精确度下降,这是没有风险的),而再将一个浮点型结果赋值给 int 型的money_kid,编译器会自动强制类型转换(这是有风险的,因为转化之后精度变低了,会造成小数位数据丢失)。而我们不必将 money_kid设置为浮点型,因为我们把控了表达式结果一定是整数,那么做强制类型转化无影响(如计算 20*0.1结果为浮点型 2.0,由于要传给int型,那么2.0会强制转化成2再赋值)。
一点改进
其实上面的方法是可以改进的,因为有一些枚举是无效的,可以通过优化来减少枚举次数。我们在枚举的时候是按照小孩、男人、女人的顺序进行枚举的。根据一些规律,我们可以对我们枚举过程进行剪枝操作:
首先要分清楚,枚举操作有两层循环。我们再枚举小孩人数的时候是对应的外层循环,枚举男人、女人人数的时候对应的是内层循环。
- 正在枚举小孩人数时,若当前枚举的小孩的门票钱数已经超过了120,那么我们可以直接(不必再枚举)结束外层循环了:因为越往后循环,我们枚举的小孩的人数只会越多,肯定小孩的门票钱数都超过了120,故找不到总钱数等于120的情况了。
- 在已确定小孩人数下,枚举的男人和女人的人数。若总门票钱数已经超过了120,那么我们可以直接(不必再枚举男人与女人)结束内层循环了:因为越往后循环,男人的人数会越来越多,女人的人数会越来越少,由于男人的票价是最贵的,那么再往后枚举,总钱数只会越来越多,一定也超过120。
改进后的代码:
#include <stdio.h> //导入stdio.h库,里面包含输入输出函数
int main() {
int n; //定义一个整型变量,用于存储总人数
scanf("%d", &n); //处理输入
int num_of_kid, num_of_woman, num_of_man; //分别存储小孩、女人、男人的人数
int money_kid, money_woman, money_man; //分别存储小孩、女人、男人的门票钱
int flag = 0; //若flag = 1则表示有答案输出,否则没有
/* 循环考虑每一种情况 */
for (num_of_kid = 0; num_of_kid <= n; num_of_kid += 10) {
money_kid = num_of_kid * 0.1; //计算小孩的门票钱
if (money_kid > 120)
break;
for (num_of_man = 0; num_of_man <= n - num_of_kid; num_of_man++) {
num_of_woman = n - num_of_kid - num_of_man;
money_woman = num_of_woman * 2; //计算女人的门票钱
money_man = num_of_man * 5; //计算男人的门票钱
if (money_kid + money_woman + money_man > 120)
break;
/* 判断该情况下是否满足条件 */
if (money_kid + money_woman + money_man == 120) {
flag = 1; //标记有输出
printf("%d,%d,%d\n", num_of_man, num_of_woman, num_of_kid); //输出结果
}
}
}
if (flag == 0) //若一直没有输出
printf("No output\n");
}
注意:
- break 的使用位置与含义
- 如果内循环是先确定女人人数再确定男人人数,那么if内应该判断是否小于120
有任何问题欢迎评论交流,如果本文对您有帮助不妨点点赞,嘻嘻~
end
欢迎关注个人公众号“ 鸡翅编程 ”,这里是认真且乖巧的码农一枚。
---- 做最乖巧的博客er,做最扎实的程序员 ----
旨在用心写好每一篇文章,平常会把笔记汇总成推送更新~



被折叠的 条评论
为什么被折叠?



