这题是我在XDOJ中长时间以来没有做出来的三道题目之一。有一次无意中发现这道题是五星级难题,连老师都说这题是他认为XDOJ中较难的题之一。好吧,不扯理由了,说白了,还是我太菜了,最后直到老师把他的题解发出来我才把这题做出来。
这题最棘手的是在数字之间加入’ '运算符,额,我先贴题目吧。
标题
构造表达式
类别
综合
时间限制
1S
内存限制
100Kb
问题描述
给定一个表示序列长度的整数n(3<=n<=9)。在序列1 2 3…n中插入‘+’,‘-’,
‘ ’构造表达式,插入‘ ’表示前后两个数字构成一个整数,例如1 2 -3 -4 -5=0。
输出构造的所有表达式中,结果为0的表达式的数量,例如n=3时,只有表达式1+2-3=0,
输出结果为1。
这题最棘手的是在数字之间加入’ ‘运算符
如果数字之间只可能有’+‘和’-’,那么只需要对运算符用递归进行排列组合,然后判断结果是否为0
很显然,’ ‘运算符需要优先考虑,然后同样只需要考虑’+‘和’-‘像上一行所说的一样
算法中定义一个op[9]字符数组专门储存运算符,因为n<=9,所以数字之间的运算符最多有8个,再加上’\0’,数组长度总共为9
输入说明
输入数据为一个整数n(n<10),表示序列长度,同时表示输入序列为“1 2 3…n”。
这个序列非常特殊,op数组中下标为index的运算符(即op[index])的两侧的数的值分别为index+1与index+2
例如:op[0]是第一个运算符,那么这个运算符两侧的数的值分别为1与2
输出说明
对于每一组数据,输出一个整数,表示构造的表达式中结果为0的表达式数量。
输入样例
3
输出样例
1
下面是老师的代码:(如果你跟我同班,那就不用看了。什么?你是我老师?千万别让我挂科,你看我都这么努力了来这里发题解)
#include <cstdio>
#include <cstring>
int n;
char op[9];
int idx; // compute函数求解过程中扫描的操作符数组当前索引,初值为0,每次compute函数调用时会清零,用于compute和get_num、get_op共享
int count; // 解的数量,在compute函数中每遇见一个符合条件的解,这里增加1
// 从当前操作符idx索引开始向后扫描,合并所有的数字(即' '操作符连接的数字)
// 返回合并后的数字
int get_num()
{
// 注意idx+1和idx+2的值,在这里idx代表操作符数组索引,因为本题中数列为1开始递增的自然数,因此我们不用单独保存数列的值,而是通过idx间接计算得到操作符左、右的数列数字,它们分别是idx+1,idx+2
// Why? 操作符索引idx以0为第一个元素,因为第一个操作符应出现在数列1、2数字之间,因此建立映射关系为idx+1,idx+2
// get_num函数会持续扫描直到遇到的操作符不是' ',这样可以连续合并多个数字,它会遇到第一个不是' '操作符时退出,见compute
int d = idx+1;
while(op[idx] == ' ' && idx < n-1)
{
d = d*10 + (idx+2);
idx++;
}
return d;
}
// 从当前位置获取(+/-)操作符,get_op函数当前位置可能有两种情况:1、已到操作符数组末尾 (想象一下只有' '操作符的情况);2、当前位置必为'+'/'-',因为get_op之前会调用get_num,见上面描述
// get_op返回的是+1或者-1或者0,0代表结束,+1代表+运算符,-1代表-运算符 ,为何这么取值?见compute