习题:
现在有两种面值的邮票,一种为8角,一种为6角。你要付n角的邮资(不能多付也不能少付),请给出邮票张数最少的方案。如果没有正好的方案则输出-1。
输入格式:
只有一行,为若干个整数(至少有两个)。这些整数最后一个整数一定是-1(输入结束标志,无需处理),其他整数均大于0,这些大于0的整数代表邮资。
输出格式:
若干行,每行依次对应输入的一个邮资,如果该邮资有正好的方案,则为两个用空格分隔的整数,代表张数最少的方案。前边的数字代表需要的8角的邮票的张数,后边的数字代表6角的邮票的张数;如果该邮资没有正好的方案则输出-1。测试用例保证所有整数均可以用int存储。。
输入样例:
24 14 11 -1
输出样例:
3 0
1 1
-1
代码1如下:
#include <stdio.h>
int main()
{
int n = 0;
int x, y;
while (1)
{
again:
scanf("%d", &n);
if (n != -1)
{
for (x = 0; x <=n/6; x++)
{
for (y = 0; y <=n/8; y++)
{
if ((6*x + 8*y) == n)
{
printf("%d %d\n", y, x);
goto again;
}
}
}
printf("-1\n");
}
else
{
break;
}
}
return 0;
}
运行结果如下:
代码2如下:
#include <stdio.h>
int ba;
int main() {
int n;
while (1) {
scanf("%d", &n);
if (n == -1)break;
ba = n / 8;
int tt = 1;
while (ba >= 0) {
if ((n - ba * 8) % 6 == 0) {
printf("%d %d\n", ba, (n - ba * 8) / 6);
tt = 2;
break;
}
ba -= 1;
}
if (tt == 1)printf("-1\n");
}
}
运行结果如下:
下面进行代码解读:
代码1:
x代表6角面值,y代表8角面值,n代表总面值,在外层循环中,循环变量x
的取值范围是从0
到n/6
,内层循环中循环变量y
的取值范围是从0
到n/8
。这种按照从小到大的顺序去遍历所有可能的x
和y
的取值组合,本质上是一种穷举的方式。由于循环是从最小的可能值(也就是0
)开始逐步增加,当第一次找到满足6*x + 8*y == n
条件的x
和y
时,它们在当前的穷举顺序下就是使得x + y
相对最小的组合。
举例来说,如果n = 24
,外层循环x
会先取0
,然后内层循环y
从0
开始取值,当y = 3
(此时8 * 3 = 24
,x
还是0
)时就满足条件了,因为循环从最小开始尝试,所以优先找到的就是数之和相对最小的组合(这里x + y = 0 + 3 = 3
),不会出现先找到其他更大和的组合情况,比如x = 4
(6 * 4 = 24
,此时y = 0
,x + y = 4
)这种相对和更大的情况会在满足条件的更小组合之后才会去尝试到(但因为已经找到组合并输出了,后续更大和的情况就不会再去管了)。
因此应该在x循环下遍历y才能保证最小。
代码2:
-
外层循环对
ba
(y
的取值调整)的控制:代码中首先计算ba = n / 8
,这里是确定了y
(也就是对应8
的倍数的数量)的初始最大可能值。然后进入while (ba >= 0)
循环,这个循环会从这个最大可能值开始,逐步递减ba
(也就是y
的取值逐步减少)。这种从大到小尝试y
的取值方式是关键所在。因为在尝试用6
和8
的倍数组合去凑n
的过程中,优先考虑让较大的数(这里是8
)尽可能多地参与,这样得到的组合中两个数的和相对会更小。例如,如果n = 24
,一开始ba = 24 / 8 = 3
,此时会先检查3
个8
能否满足情况,发现满足(因为24 - 3 * 8 = 0
,0
能被6
整除),那就直接找到了y = 3
,x = 0
的组合(x + y = 3
),这就是数之和最小的组合。如果不先从大的y
值开始尝试,可能会先找到其他x
、y
值更大的组合来凑n
,比如先从y = 0
开始尝试,然后不断增加x
去凑,可能就会先找到x = 4
,y = 0
这样x + y = 4
的相对更大的组合了。 -
内层条件判断对
x
((n - ba * 8) % 6 == 0
部分)的确定:在每次ba
(y
的取值)确定后,通过(n - ba * 8) % 6 == 0
这个条件来判断,剩余的数(也就是n
减去当前y
个8
之后剩下的部分)能否被6
整除。如果能整除,那就意味着找到了满足6 * x + 8 * y = n
的x
(即(n - ba * 8) / 6
)和y
(即ba
)的一组值。 而且由于外层循环是从大到小递减y
的取值,一旦找到满足条件的组合,就是按照这种有利于数之和最小的顺序下最先出现的组合,后续即使继续递减y
再找,得到的组合中两数之和也只会更大(因为优先是让较大数8
尽可能多地参与凑数了),所以此时找到的组合就是x + y
最小的组合。
本期练习讲解就到这里~~~
往期回顾:
C语言——指针初阶(三)-****博客
C语言——指针初阶(二)-****博客
C语言——海龟作图(对之前所有内容复习)_c语言画图小动物代码-****博客
C语言——指针初阶(一)-****博客
C语言函数递归经典题型——汉诺塔问题_汉诺(hanoi)塔问题-****博客
C语言——数组基本知识(二)_c语言四维数组的使用方法-****博客
C语言——数组基本知识(一)-****博客
C语言——数组逐元素操作练习-****博客
C语言编程练习:验证哥德巴赫猜想 进制转换 rand函数-****博客