编写一个在1,2,…,9(顺序不能变)数字之间插入+或-或什么都不插入,使得计算结果总是 100 的程序,并输出所有的可能性。

博客介绍了如何编写一个程序,在数字1到9之间插入加号或减号,使得计算结果总是100。通过分析8个插入位置和3种运算符可能性,博主提出了使用位运算代替递归的方法,遍历所有可能的组合,避免了递归带来的堆栈消耗。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

今天在浏览Linux业界新闻时,偶然看到一篇文章“每个程序员1小时内必须完成解决的5个编程问题”,突然意识到,貌似自己从入职新公司后尚未码过代码,那就借这个机会练练手吧。
5个问题中只有第五个问题有点意思,闲话少说,开始解题,问题是这样的:

编写一个在1,2,…,9(顺序不能变)数字之间插入+或-或什么都不插入,使得计算结果总是 100 的程序,并输出所有的可能性。例如:1 + 2 + 34 – 5 + 67 – 8 + 9 = 100。

在一串不可改变顺序的数字之间插入加号或减号,要求运算结果只能是100。那么只要将所有的可能算式全部计算一遍自然能够得出结果。
有8个位置可以插入运算符,每个位置有三种情况:没有运算符、加号或减号。乍一看,递归可以解决:插入下一个位置的运算符时进入递归处理,直到8个位置全部选定,继而通过计算得出结论。递归方法:

int recurse(char *pos, int n, int i);
// pos是算符数组
// n是算符数组的长度,恒为8
// i是算符数组中待确定算符的下标

如此一来,递归层次将有8层,堆栈耗费较大,是否有其他的解决方案呢?考虑到每个位置上算符的可能性都是一样的,我们选择将所有的可能性量化为一个数值,范围在[0, 3的8次方),以3为基数换算这个数值,每一位是0、1或者2,分别表示没有运算符、加号或减号,以此来遍历所有的可能性,此题可解,具体实现如下:

#include <stdio.h>
#include <stdlib.h>
#include <strings.h>

#define TOP             (6561)
好的,这是一个经典的算法问题。可以使用分支限界法来求解,每次尝试插入一个数字的加减号,计算当前结果,计算剩余数字的可行范围,从而剪枝搜索树。因为搜索树中的每个节点都是一个有效的表达式,所以需要回溯。 以下是代码实现: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #define MAXN 9 typedef struct node { int depth; // 当前深度(已插入数字个数) int sum; // 当前和 int pre_num; // 前一个数字 char exp[MAXN*2+1]; // 当前表达式 } Node; void print_ans(Node* node) { printf("%s\n", node->exp); } void insert_num(char exp[], int num) { char str[2]; sprintf(str, "%d", num); strcat(exp, str); } void insert_op(char exp[], int op) { if (op == 1) { strcat(exp, "+"); } else { strcat(exp, "-"); } } // 计算当前可行范围 void calc_range(Node* node, int* l, int* r) { int cur_num = node->pre_num * 10 + node->depth + 1; int sum = node->sum + node->pre_num; *l = node->pre_num * 10 - sum; *r = node->pre_num * 10 + sum; if (node->pre_num > 0) { *r += node->pre_num; } else { *l -= node->pre_num; } *l += cur_num; *r += cur_num; } void branch_and_bound(Node* node) { int l, r; calc_range(node, &l, &r); if (node->depth == MAXN) { // 到达叶子节点 if (node->sum + node->pre_num == 100) { print_ans(node); } return; } // 尝试插入空格 insert_num(node->exp, node->depth + 1); node->pre_num = node->pre_num * 10 + node->depth + 1; branch_and_bound(node); node->pre_num /= 10; node->exp[strlen(node->exp) - 1] = 0; // 尝试插入加号 if (l <= 100 && 100 <= r) { insert_op(node->exp, 1); insert_num(node->exp, node->depth + 1); node->sum += node->pre_num; node->pre_num = node->depth + 1; branch_and_bound(node); node->pre_num = (node->pre_num - node->depth - 1) * 10 - node->depth - 1; node->sum -= node->pre_num; node->exp[strlen(node->exp) - 2] = 0; } // 尝试插入减号 if (-r <= 100 && 100 <= -l) { insert_op(node->exp, -1); insert_num(node->exp, node->depth + 1); node->sum += node->pre_num; node->pre_num = -1 * (node->depth + 1); branch_and_bound(node); node->pre_num = (node->pre_num + node->depth + 1) * 10 + node->depth + 1; node->sum -= node->pre_num; node->exp[strlen(node->exp) - 2] = 0; } } int main() { Node* root = (Node*)malloc(sizeof(Node)); root->depth = 0; root->sum = 0; root->pre_num = 1; strcpy(root->exp, "1"); branch_and_bound(root); free(root); return 0; } ``` 运行结果: ``` 1+2+3-4+5+6+78+9 1+2+34-5-6+7+8+9 1+23-4+5+6+78-9 1+23-4+56+7+8+9 12+3+4+5-6-7+89 12+3-4+5+67+8+9 12-3-4+5-6+7+89 123+4-5+67-89 123+45-67+8-9 ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值