参考 https://blog.csdn.net/linhaiyun_ytdx/article/details/50629743
如果只有5个砝码,重量分别是1,3,9,27,81。已知它们可以组合称出1到121之间任意整数重量(砝码允许放在左右两个盘中)。
本题目要求编程实现:对用户给定的重量,给出砝码组合方案。
例如:
用户输入:
5
程序输出:
9-3-1
用户输入:
19
程序输出:
27-9+1
要求程序输出的组合总是大数在前小数在后。
可以假设用户的输入的数字符合范围1~121。
————————————————
版权声明:本文为CSDN博主「潇潇雨歇_」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/linhaiyun_ytdx/article/details/50629743
查资料的时候,碰到这个问题,索性把所有的砝码相关的算法题都总结一边。下面是自己实现的方案。
最简单的穷举法
char a[] = { 1, 3, 9, 27, 81 }; int num = 0; cin >> num; for (int i0 = -1; i0 < 2; i0++) { for (int i1 = -1; i1 < 2; i1++) { for (int i2 = -1; i2 < 2; i2++) { for (int i3 = -1; i3 < 2; i3++) { for (int i4 = -1; i4 < 2; i4++) { if (num == (a[0] * i0 + a[1] * i1 + a[2] * i2 + a[3] * i3 + a[4] * i4)) { cout << i0 << i1 << i2 << i3 << i4; } } } } } }
把穷举法改成递归
bool test(char* a, int index, int nownum, int num, char* b) { if (index == 5) { return false; } int tmp = nownum; b[index] = 0; if (nownum == num) { return true; } else if (test(a, index + 1, nownum, num, b)) { return true; } b[index] = -1; nownum = tmp - a[index]; if (nownum == num) { return true; } else if (test(a, index + 1, nownum, num, b)) { return true; } b[index] = 1; nownum = tmp + a[index]; if (nownum == num) { return true; } else if (test(a, index + 1, nownum, num, b)) { return true; } b[index] = 0; return false; } int main() { char a[] = { 1, 3, 9, 27, 81 }; char b[5] = { 0 }; int num = 0; cin >> num; test(a, 0, 0, num, b); }
这样可以看出重复的计算非常多,那么给定的题目有没有规律呢?参考上面作者的思路,我们发现1只能表示1;1和3呢,最大可以表示到4;1,3,9呢,可以表示到13,就是与斐波那契数列一样相加,得到一个区间,那么在每个区间内,比如如果数字在1和3生成的区间1-4内,肯定是有1和3组成的,并且大于1的数字,肯定需要3.因为都只有一个砝码,不可能砝码a可以称出大于a自己质量的物品。如果是在5-13之间的数字呢?那么就肯定需要9.所以我们先找到最大的数字,然后用输入的数字减去最大的数字,如果是正数,表示还大,再减去第二小的数字;如果是负数,表示小了,就加上下一个数字。放到天平上也是,如果物品是4,那么我们先放一个3,再放一个1.如果是5呢,我们先放一个9,因为1和3都加上也压不起4,所以要更大的9,放了9,天平朝砝码倾斜,表示多了,所以要在物品这边加上砝码,把多余的重量(也就是相减的负值)抵消掉。既然是砝码帮助抵消的重量,所以计算的时候要减去这部分不输入物品的砝码的重量。
int main() { int a[] = { 1, 3, 9, 27, 81 }; int b[5] = { 0 }; for (int i = 0; i < 5; i++) { if (i > 0) { b[i] = a[i] + b[i - 1]; } else { b[i] = a[i]; } } int num = 0; cin >> num; while (num != 0) { int index = 0; for (int i = 0; i < 5; i++) { if (std::abs(num) <= b[i]) { index = i; break; } } if (num > 0) { cout << "+" << a[index]; } else if (num < 0) { cout << "-" << a[index]; } if (num > 0) { num = num - a[index]; } else if (num < 0) { num = num + a[index]; } } char inchar; cin >> inchar; }