题目描述:
输入一个正整数X,在下面的等式左边的数字之间添加+号或者-号或者不填,使得等式成立。
1 2 3 4 5 6 7 8 9 = X
12-34+5-67+89 = 5
1+23+4-5+6-7-8-9 = 5
请编写程序,统计满足输入整数的所有等式个数。
输出: 使该等式成立的个数
样例输出:21
代码:
#include<iostream>
#include<string>
#include<stack>
#include<cmath>
using namespace std;
string inFixToPostFix(string expr)//简化的(没有*/和括号)中缀表达式转后缀表达式,细节见我的表达式计算博文,略有修改
{
stack<char> opt;
string res = "";
int len = expr.size();
for (int i = 0; i < len; i++)
{
if (isdigit(expr[i]))
{
res += expr[i];
}
else if(expr[i] == ' ')
{
continue;
}
else
{
if (i && isdigit(expr[i-1]))
{
res += ";";
}
if (opt.empty())
{
opt.push(expr[i]);
}
else
{
while (!opt.empty())
{
res += opt.top();
res += ";";
opt.pop();
}
opt.push(expr[i]);
}
}
}
while(!opt.empty())
{
res += ";";
res += opt.top();
opt.pop();
}
res += ";";//这一句,是hack的做法,为了避免整个表达式就是123这种情况(没有操作符)
return res;
}
int evalPostFix(string expr)//简化的后缀表达式计算
{
int res = 0;
stack<int> opr;
int len = expr.size();
int i, j;
for (i = 0; i < len; i++)
{
if (expr[i] == ';')
{
continue;
}
else if (isdigit(expr[i]))
{
int num = 0;
for (j = i; expr[j] != ';'; j++)//配合上面的;分割和结束判断
{
num = num * 10 + expr[j] - '0';
}
opr.push(num);
i = j;
}
else
{
int right = opr.top();
opr.pop();
int left = opr.top();
opr.pop();
int t;
switch(expr[i])
{
case '+':
t = left + right;
opr.push(t);
break;
case '-':
t = left - right;
opr.push(t);
break;
}
}
}
res = opr.top();
return res;
}
int main()
{
string s = "1 2 3 4 5 6 7 8 9";
int num;//等式右边的数字
while(cin >> num)
{
int count = 0;//使等式成立的表达式个数
int maxVaule = (int)pow(3, 8);//9个数字之间的8个位置,每个位置可以放置3种字符
char select[] = " +-";//可选的字符列表
for(int i = 0; i < maxVaule; i++)//枚举,把每个整数转化为相应的3进制数,然后改变等式左边的表达式
{
int t = i;
for(int j = 1; j <= 15 ; j += 2)
{
s[j] = select[t%3];
t /= 3;
}
if(evalPostFix(inFixToPostFix(s)) == num)//计算表达式的值
{
count++;
cout << s << endl;
}
}
cout << count << endl;
}
return 0;
}
结果:
当然,此题完全可以用DFS做,或者使用8重for循环计算,由于要求的是所有满足条件的等式个数,所以只能枚举,不可能更高效。