题目描述: 标题 构造表达式 类别 综合 时间限制 1S 内存限制 100Kb 问题描述 给定一个表示序列长度的整数n(3<=n<=9)。在序列1 2 3…n中插入‘+’,‘-’,‘ ’构造表达式,插入‘ ’表示前后两个数字构成一个整数,例如1 2 -3 -4 -5=0。 输出构造的所有表达式中,结果为0的表达式的数量,例如n=3时,只有表达式1+2-3=0,输出结果为1。 输入说明 输入数据为一个整数n(n<10),表示序列长度,同时表示输入序列为“1 2 3…n”。 输出说明 对于每一组数据,输出一个整数,表示构造的表达式中结果为0的表达式数量。 输入样例 3 输出样例 1
整体思路:
可将‘+’,‘-’,以及‘ ’ 分别用mode的三个值0、1、2来代表。故建立数组mode[],用来存储每两位整数之间的运算。
此时可将整数部分(num)和插入的运算符号(mode)看做互相独立的两个部分。
因此,要遍历不同运算模式,只需将数组mode[]的值做遍历,每次再根据对应的mode组合对整数做运算即可。
遍历思路:
在此参照for循环原理,联想到x进制数进位的规则,因此,可将遍历三种模式在各位上的不同组合的这一多层嵌套循环结构,看成三进制数的进位。
因此可写出遍历函数cycle()
int cycle(int * mode, int n)
{
int i, SUM = 0;
n = n - 2; //调整下标优先适合mode[]数组
while(mode[0] < 3)
{
/*对mode数组最后一位递增循环,并在每次循环组成新mode序列时计算表达式数值
当mode[n]递增至3时,向前位进一并重置末位mode[n]*/
for(mode[n] = 0; mode[n] < 3; mode[n]++)
{
SUM += compute(mode, n);
}
//进位操作
for(i = n; i >= 0; i--)
{
if(mode[i] == 3)
{
mode[i] = 0;
mode[i-1]++;
//若最高位进至3,则已经完成遍历,跳出循环
if(mode[0] == 3)
break;
}
else break;
}
}
return (SUM);
}
有了遍历函数,就只需再写出整数按照遍历过程中每次形成的mode组合进行运算的函数compute()
计算思路:
计算思路本身并不复杂,只需分'+''-'和' '三种情况,依次对相邻整数操作即可。但实际编写过程中,实现' '即前后数字组合成新数这一算法出现了很多之前意想不到的错误和漏洞,如:前卫数字结合到了后位上时,原位置前的运算操作如何继承?若数字从后位开始向前结合,前位数字需要乘以10的次方数需要额外代码确定(即算出已经结合部分的位数),导致复杂化等等的问题。
因此,考虑在对NUM按mode进行其他运算之前,先查找出mode[2](即' ',结合)运算,并将需要结合的数字结合到位置靠前的那项上,以解决上述运算操作继承问题,同时,将以被结合的数字清为0,保证它们不会影响运算。
之后,就只需考虑'+''-'两种运算,遇到结合运算直接跳过即可。因此可以写出compute()函数:
int compute(int *mode, int n)
{
int sum, i, temp;
int NUM[most] = {0};
//用NUM数组拷贝num数组
for(i = 0; i <= n + 1; i++)
{
NUM[i] = num[i];
}
for(i = 0; i <= n; i++)
{
//' ',即结合运算
if(mode[i] == 2)
{
int I = i;//记录下需要结合的第一项的位置
while(mode[i] == 2)
{
NUM[I] = NUM[I] * 10 + NUM[i+1];
NUM[i+1] = 0;
i++;
}
}
}
for(i = 0, sum = NUM[0]; i <= n; i++)
{
if(mode[i] == 0)
sum += NUM[i+1];
else if(mode[i] == 1)
sum -= NUM[i+1];
else if(mode[i] == 2)
continue;
}
if(sum == 0)
return 1;
else
return 0;
}
到此,已经可以写出完整的代码:
#include <stdio.h>
#include <math.h>
int cycle(int * mode, int n);
int compute(int *mode, int n);
#define most 9
int num[most] = {0};
int main()
{
int i, n, SUM;
scanf("%d", &n);
int mode[9] = {0};
for(i = 0; i < most; i++)
{
num[i] = i + 1;
}
SUM = cycle(mode, n);
printf("%d", SUM);
return 0;
}
int cycle(int * mode, int n)
{
int i, SUM = 0;
n = n - 2; //调整下标优先适合mode[]数组
while(mode[0] < 3)
{
/*对mode数组最后一位递增循环,并在每次循环组成新mode序列时计算表达式数值
当mode[n]递增至3时,向前位进一并重置末位mode[n]*/
for(mode[n] = 0; mode[n] < 3; mode[n]++)
{
SUM += compute(mode, n);
}
//进位操作
for(i = n; i >= 0; i--)
{
if(mode[i] == 3)
{
mode[i] = 0;
mode[i-1]++;
//若最高位进至3,则已经完成遍历,跳出循环
if(mode[0] == 3)
break;
}
else break;
}
}
return (SUM);
}
int compute(int *mode, int n)
{
int sum, i, temp;
int NUM[most] = {0};
//用NUM数组拷贝num数组
for(i = 0; i <= n + 1; i++)
{
NUM[i] = num[i];
}
for(i = 0; i <= n; i++)
{
//' ',即结合运算
if(mode[i] == 2)
{
int I = i;//记录下需要结合的第一项的位置
while(mode[i] == 2)
{
NUM[I] = NUM[I] * 10 + NUM[i+1];
NUM[i+1] = 0;
i++;
}
}
}
for(i = 0, sum = NUM[0]; i <= n; i++)
{
if(mode[i] == 0)
sum += NUM[i+1];
else if(mode[i] == 1)
sum -= NUM[i+1];
else if(mode[i] == 2)
continue;
}
if(sum == 0)
return 1;
else
return 0;
}
以上仅为个人作为初学者的一些思考和理解,如有谬误或更加优秀的解法还请不吝赐教!:)