无优先级运算问题 问题描述:给定n个正整数和4个运算符+、-、*、/,且运算符无优先级,如2+3x5=25。对于任意给定的整数m, 试设计一个算法,用以上给出的n个数和4个运算符,产生整数m,且用的运算次数最少。给出的n个数中每个数最多只能用1次,但每种运算符可以任意使用。 算法设计:对于给定的n个正整数, 设计一个算法,用最少的无优先级运算次数产生整数m。 数据输入: 由文件input.txt给出输入数据。 第1行有2个正整数n和m。 第2行是给定的用于运算的n个正整数。 结果输出: 将计算的产生整数 m 的最少无优先级运算次数以及最优无优先级运算表达式输出到文件output.txt。回溯法C语言代码及注释
时间: 2023-11-28 09:49:07 浏览: 169
下面是使用回溯法解决该问题的 C 语言代码及注释:
```c
#include <stdio.h>
#include <stdlib.h>
int n, m; // n: 数字个数;m: 目标数字
int nums[10]; // 存储数字
char ops[4] = {'+', '-', '*', '/'}; // 四种运算符
char expr[10]; // 存储最优表达式
int min_op_count = 10; // 最少操作次数,初始值为一个较大的数
// 计算表达式的值
int evaluate(char *expr, int len) {
// 初始化操作数和操作符栈
int nums[len];
char ops[len];
int num_top = -1, op_top = -1;
for (int i = 0; i < len; i++) {
if (expr[i] >= '0' && expr[i] <= '9') { // 如果是数字,将其入栈
num_top++;
nums[num_top] = expr[i] - '0';
} else { // 如果是操作符
while (op_top >= 0 && (ops[op_top] == '*' || ops[op_top] == '/') && (expr[i] == '+' || expr[i] == '-')) { // 遇到加减号,先将乘除号出栈并计算
int b = nums[num_top];
num_top--;
int a = nums[num_top];
num_top--;
if (ops[op_top] == '*') {
nums[++num_top] = a * b;
} else {
nums[++num_top] = a / b;
}
op_top--;
}
// 将操作符入栈
op_top++;
ops[op_top] = expr[i];
}
}
while (op_top >= 0) { // 进行加减运算
int b = nums[num_top];
num_top--;
int a = nums[num_top];
num_top--;
if (ops[op_top] == '+') {
nums[++num_top] = a + b;
} else {
nums[++num_top] = a - b;
}
op_top--;
}
return nums[num_top];
}
// 回溯函数
void backtrack(int cur_op_count, int cur_num_count, char *cur_expr) {
if (cur_num_count == n) { // 如果已经使用了所有数字
int value = evaluate(cur_expr, n * 2 - 1); // 计算表达式的值
if (value == m) { // 如果值等于目标值
if (cur_op_count < min_op_count) { // 更新最少操作次数和最优表达式
min_op_count = cur_op_count;
for (int i = 0; i < n * 2 - 1; i++) {
expr[i] = cur_expr[i];
}
}
}
} else {
// 对于每个数字,可以选择使用或不使用
// 如果选择使用,则可以添加四种运算符中的任意一种
for (int i = 0; i < 2; i++) { // i=0表示不使用当前数字,i=1表示使用当前数字
if (i == 0 || (cur_num_count > 0 && cur_expr[(cur_num_count - 1) * 2 + 1] != '/')) { // 判断是否可以添加除法符号
if (i == 1) { // 添加当前数字
cur_expr[cur_num_count * 2 - 1] = nums[cur_num_count];
}
if (cur_op_count < min_op_count - 1) { // 剪枝:如果当前操作次数已经大于等于最少操作次数减1,则不再继续搜索
for (int j = 0; j < 4; j++) { // 添加运算符
cur_expr[cur_num_count * 2] = ops[j];
backtrack(cur_op_count + 1, cur_num_count + 1, cur_expr); // 继续搜索下一个数字
}
}
if (i == 1) { // 恢复当前表达式
cur_expr[cur_num_count * 2 - 1] = ' ';
}
}
}
}
}
int main() {
// 读入数据
scanf("%d%d", &n, &m);
for (int i = 0; i < n; i++) {
scanf("%d", &nums[i]);
}
// 开始回溯
char cur_expr[n * 2 - 1];
for (int i = 0; i < n * 2 - 1; i += 2) {
cur_expr[i] = nums[i / 2] + '0';
}
backtrack(0, 1, cur_expr);
// 输出结果
printf("%d\n", min_op_count);
for (int i = 0; i < n * 2 - 1; i++) {
printf("%c", expr[i]);
}
printf("\n");
return 0;
}
```
该算法的时间复杂度为 $O(4^n)$,空间复杂度为 $O(n)$。在实际运行中,由于使用了剪枝,可以大大缩短时间复杂度。
阅读全文