马戏团观众人数

写在前面:

题解是对具体题目的编程实现,不会具体讲解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. 60↵
 
  1. 0,60,0↵
  2. 19,11,30↵
1秒64M0

题解

本题可以直接枚举三种人的人数,找到在该人数条件下满足收入为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再赋值)。


一点改进

其实上面的方法是可以改进的,因为有一些枚举是无效的,可以通过优化来减少枚举次数。我们在枚举的时候是按照小孩、男人、女人的顺序进行枚举的。根据一些规律,我们可以对我们枚举过程进行剪枝操作:

首先要分清楚,枚举操作有两层循环。我们再枚举小孩人数的时候是对应的外层循环,枚举男人、女人人数的时候对应的是内层循环。

  1. 正在枚举小孩人数时,若当前枚举的小孩的门票钱数已经超过了120,那么我们可以直接(不必再枚举)结束外层循环了:因为越往后循环,我们枚举的小孩的人数只会越多,肯定小孩的门票钱数都超过了120,故找不到总钱数等于120的情况了。
  2. 在已确定小孩人数下,枚举的男人和女人的人数。若总门票钱数已经超过了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");
}

 注意:

  1. break 的使用位置与含义
  2. 如果内循环是先确定女人人数再确定男人人数,那么if内应该判断是否小于120


有任何问题欢迎评论交流,如果本文对您有帮助不妨点点赞,嘻嘻~ 


end 

欢迎关注个人公众号 鸡翅编程 ”,这里是认真且乖巧的码农一枚。

---- 做最乖巧的博客er,做最扎实的程序员 ----

旨在用心写好每一篇文章,平常会把笔记汇总成推送更新~

在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值