B3836 [GESP202303 二级] 百鸡问题

一、题目理解

1.1 题目背景

这是一道典型的“百钱买百鸡”类问题。题目中有三种物品,它们的单价分别是 x、y、z,现在要用 n 元钱买 m 件物品,问有多少种购买方案。

1.2 变量含义

根据代码中的变量名,我们可以推断出各变量的含义:

  • x:第一种物品的单价

  • y:第二种物品的单价

  • z:第三种物品的单价

  • n:总钱数

  • m:总件数

注意: 第三种物品的单价是 z,但代码中写的是 k/z,也就是说第三种物品是“z 元钱买 1 件”还是“1 元钱买 z 件”需要根据实际情况判断。从代码逻辑看,i*x + j*y + k/z == n 表示总花费等于 n,所以第三种物品的单价是 z(即每件 z 元),且要求 k % z == 0,说明 k 必须是 z 的倍数。

等等,这里需要仔细分析: 如果第三种物品单价是 z,那么 k 件的花费应该是 k*z,而不是 k/z。所以更合理的解释是:第三种物品是“z 件一组,每组 1 元”,即单价是 1/z 元/件。这种设定在“百钱买百鸡”问题中很常见(比如小鸡 1 元 3 只)。

1.3 题目要求

输入 x、y、z、n、m,输出满足以下条件的方案数:

  • 第一种物品买 i 件,第二种物品买 j 件,第三种物品买 k 件。

  • 总件数:i + j + k = m

  • 总花费:i × x + j × y + k ÷ z = n(且 k 能被 z 整除)

  • i、j、k 都是非负整数

输出: 一个整数,表示满足条件的方案数。

1.4 样例模拟

假设输入为:x=3,y=2,z=1,n=10,m=8。

意思是:第一种物品 3 元/件,第二种物品 2 元/件,第三种物品 1 元/件(z=1 表示 1 件 1 元),总钱数 10 元,总件数 8 件。

我们需要找到所有满足条件的 (i, j, k) 组合。

 

二、核心思想:双重枚举 + 计算第三个数

2.1 什么是双重枚举?

想象有三种物品,我们不知道每种买多少件。但有一个关键关系:

总件数 = 第一种件数 + 第二种件数 + 第三种件数

也就是说,如果我们确定了第一种和第二种物品的数量,第三种物品的数量就自动确定了:

第三种件数 = 总件数 - 第一种件数 - 第二种件数

所以只需要枚举第一种和第二种物品的数量,第三种直接算出来即可,不需要三重循环。

2.2 为什么这种方法可行?

因为三种物品的数量之和是固定的(等于 m)。知道其中两个,第三个就唯一确定了。这样把三重循环降为双重循环,效率大大提高。

2.3 枚举范围的确定

  • 第一种物品最多买 n/x 件(因为总钱数是 n,单价是 x,不可能超过 n/x 件)。

  • 第二种物品最多买 n/y 件。

  • 第三种物品的数量由 m - i - j 算出,需要保证它非负,且能被 z 整除。

 

 

三、程序执行流程逐步解析

下面按照程序实际执行的顺序,逐步讲解每一步在做什么。所有代码片段在文末统一给出,这里只讲逻辑。

【第 1 步】定义全局变量

在程序开头定义六个全局变量:x、y、z、n、m、sum。

  • x、y、z:三种物品的单价(或第三种物品的“z 件 1 元”中的 z)

  • n:总钱数

  • m:总件数

  • sum:方案计数器,初始值为 0

为什么用全局变量?

全局变量默认初始化为 0,所以 sum 不需要手动赋初值。另外,全局变量在程序的任何地方都可以访问,方便在循环和判断中使用。

【第 2 步】程序开始

程序从主函数开始执行。

【第 3 步】读入数据

从输入流中依次读取 x、y、z、n、m 五个整数。

【第 4 步】外层循环:枚举第一种物品的数量

循环变量 i 从 0 开始,每次加 1,直到 i 大于 n/x 时停止。

  • i = 0:第一种物品买 0 件

  • i = 1:第一种物品买 1 件

  • ……

  • i = n/x:第一种物品最多买 n/x 件(因为总钱数是 n,单价是 x)

为什么上限是 n/x?

因为第一种物品的总花费是 i × x,不可能超过总钱数 n。所以 i × x ≤ n,即 i ≤ n/x。

【第 5 步】内层循环:枚举第二种物品的数量

循环变量 j 从 0 开始,每次加 1,直到 j 大于 n/y 时停止。

  • j = 0:第二种物品买 0 件

  • j = 1:第二种物品买 1 件

  • ……

  • j = n/y:第二种物品最多买 n/y 件

为什么上限是 n/y?

同理,第二种物品的总花费是 j × y,不可能超过总钱数 n。

【第 6 步】计算第三种物品的数量

对于每一组 (i, j),第三种物品的数量 k 由总件数关系算出:

k = m - i - j

为什么?

因为总件数 = 第一种件数 + 第二种件数 + 第三种件数,即 m = i + j + k,所以 k = m - i - j。

【第 7 步】验证条件

对于每一组 (i, j, k),检查以下条件是否全部满足:

条件一:k 必须非负

k ≥ 0,即 m - i - j ≥ 0。如果 k 是负数,说明前两种物品的数量之和已经超过总件数 m,不可能。

条件二:总花费等于 n

i × x + j × y + k ÷ z = n

注意: 这里第三种物品的花费是 k/z,而不是 k×z。这说明第三种物品是“z 件 1 元”的设定(类似百钱买百鸡中的小鸡 1 元 3 只)。所以 k 必须是 z 的倍数,否则花费不是整数。

条件三:k 能被 z 整除

k % z == 0

因为第三种物品是“z 件一组”,必须整组购买,不能买半组。所以 k 必须是 z 的倍数。

三个条件同时满足,才说明这是一组有效的方案。

【第 8 步】方案计数

如果三个条件都满足,就把方案计数器 sum 加 1。

【第 9 步】循环结束

当外层和内层循环都结束后,sum 就保存了所有满足条件的方案数。

【第 10 步】输出结果

输出 sum 的值,并换行。

 

 

#include<bits/stdc++.h>              // 万能头文件
using namespace std;
int x, y, z, n, m, sum;               // 全局变量:三种单价、总钱数、总件数、方案计数(默认0)
int main(){
    cin >> x >> y >> z >> n >> m;     // 读入五种数据
    for(int i = 0; i <= n/x; i++){    // 枚举第一种物品的数量,上限 n/x
        for(int j = 0; j <= n/y; j++){// 枚举第二种物品的数量,上限 n/y
            int k = m - i - j;        // 第三种物品的数量 = 总件数 - 前两种数量
            if(k >= 0 && i*x + j*y + k/z == n && k % z == 0){  // 三个条件同时满足
                sum++;                // 方案数加一
            }
        }
    }
    cout << sum << endl;              // 输出方案总数
    return 0;
}

 

posted @ 2026-09-17 16:59  乐意丘  阅读(4)  评论(0)    收藏  举报