寻找表达式(dfs)
- 题目来源:微策略2013年校园招聘笔试题
- 题目描述:
-
现在有一个序列123......N,其中N介于3和15之间,要求在序列之间加入+、-或者空格,使得该序列组成的数学表达式的运算结果为0。
- 输入:
-
输入可能包含多个测试样例。
对于每个测试案例,输入整数N(3<=N<=15),代表这个序列的长度。
- 输出:
-
对应每个测试案例,输出所有使得表达式结果为0的组合,当有多个组合时,按字典序进行排序输出。
- 样例输入:
-
3 6
- 样例输出:
-
1+2-3 1 2+3-4-5-6
- 提示:
-
1_2+3-4-5-6相当于12+3-4-5-6(‘_’代表空格)
思路:
对于3<=n<=15,总共有3^n种情况,当n=15时,总共有14348907种情况,所以对于给定的n,我们都可以在1秒内穷举完。对于穷举,当然用dfs是最方便的,我写的代码基本是对所有的情况都遍历一遍,当然如果觉得效率还不行,可以加些适当的减枝。代码如下:
1 #include <stdio.h> 2 3 int n; 4 int op[20]; 5 6 void print_ans() 7 { 8 int i; 9 10 for (i = 1; i < n; i ++) 11 { 12 printf("%d", i); 13 if (op[i] == 0) 14 printf(" "); 15 else if (op[i] == 1) 16 printf("+"); 17 else 18 printf("-"); 19 } 20 printf("%d\n", i); 21 } 22 int is_ok() 23 { 24 int i, ans, temp; 25 26 if (op[1] == 0) 27 ans = 0; 28 else 29 ans = 1; 30 i = 1; 31 while (i < n) 32 { 33 if (op[i] == 0) 34 { 35 temp = i; 36 while (i < n && op[i] == 0) 37 { 38 i ++; 39 if (i >= 10) 40 temp *= 10; 41 temp = temp * 10 + i; 42 } 43 ans += temp; 44 } 45 else if (op[i] == 1) 46 { 47 temp = ++i; 48 while (i < n && op[i] == 0) 49 { 50 i ++; 51 if (i >= 10) 52 temp *= 10; 53 temp = temp * 10 + i; 54 } 55 ans += temp; 56 } 57 else 58 { 59 temp = ++i; 60 while (i < n && op[i] == 0) 61 { 62 i ++; 63 if (i >= 10) 64 temp *= 10; 65 temp = temp * 10 + i; 66 } 67 ans -= temp; 68 } 69 } 70 return ans; 71 } 72 void dfs(int index) 73 { 74 if (index == n) 75 { 76 if (!is_ok()) 77 print_ans(); 78 return; 79 } 80 //空格 81 op[index] = 0; 82 dfs(index + 1); 83 //加 84 op[index] = 1; 85 dfs(index + 1); 86 //减 87 op[index] = 2; 88 dfs(index + 1); 89 } 90 int main(void) 91 { 92 while (scanf("%d", &n) != EOF) 93 dfs(1); 94 return 0; 95 }
关键的代码是dfs函数,分别对空格,加,减进行穷举,op[index]存放了第index位置存放的是哪种情况(0表示空格,1表示加,2表示减),如果index为n,则说明得到了一种可能,函数is_ok就是用于判断当前的情况是否能使得表达式最终的结果为0,如果为0,则输出并返回,否则直接返回。
is_ok函数是用于判断放在op数组中的表达式是否满足条件,计算表达式比较麻烦的是为空格的情况,由于空格可以首先出现,在“+”后面出现,在“-”后面出现,is_ok中的代码则依次处理这三种情况。还有就是如果空格后面是个2位数,空格前面组成的数要向左移动两位,如果是1位数,只用移动1位。