P1236 算24点
细节爆搜是真的牛逼。。。
题目意思非常的简单:给你4个数,可以任意添加运算符和括号,判断运算结果可不可能出现24?若可能输出方案的任意一种。(spj真好)
如果考虑上那些括号的话会很麻烦,于是我就翻题解发现可以使用后缀表达式来解决。
我的做法是构造一个字符串来表示一个后缀表达式,填运算符的话可以用dfs解决,注意细节就能调出来。
得到后缀表达式我们就可以求解了,如果求解的答案是24的话直接再算一次,输出我进行的那三次运算,然后exit就可以了。
整体来说就是这么简单。。。
下面是细节(毒瘤)部分
- 注意:所有的中间结果须是整数,所以一些除法运算是不允许的。
所以我们在运算的时候,当中间结果不整除的话就不行了。
- 如果两个操作数有大小的话则先输出大的。
所以在输出方案的时候碰到加法或者乘法这种满足交换律的,维护一下就ok了。
如果不这么写的话你怕是连样例都过不去。
- 注意0不能被除。(参考题解)
所以特判一下就可以了。我没有特判结果好多个RE。
- 运算中不能出现0和负数(特判解决)。(参考题解)
继续特判,加上这个我就能A了。
代码:
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<stack>
const char pp[] = {'+', '-', '*', '/'};
int a[50];
char ch[350];
int p[50];
void print()
{
for(int i = 1; i <= p[4]; i++)
{
printf("%c", ch[i]);
}
printf("\n");
}
int cal(bool printit)
{
//print();
std::stack<int> sta;
for(int i = 1; i <= p[4]; i++)
{
if(ch[i] == 0) continue;
if(ch[i] >= '0' && ch[i] <= '9') sta.push(ch[i] - '0');
else
{
char sym = ch[i];
int y = sta.top(); sta.pop();
int x = sta.top(); sta.pop();
if(sym == '/')
{
if(y == 0) return -1;
if(x / y * y != x) return -1;
sta.push(x / y);
}
else if(sym == '+')
{
if(x < y) std::swap(x, y);
sta.push(x + y);
}
else if(sym == '-') sta.push(x - y);
else if(sym == '*')
{
if(x < y) std::swap(x, y);
sta.push(x * y);
}
if(sta.top() <= 0) return -1;
if(printit) printf("%d%c%d=%d\n", x, sym, y, sta.top());
}
}
return sta.top();
}
void dfs(int t, int pre)
{
if(t == 5)
{
//print();
if(pre != 3) return;
if(cal(false) == 24)
{
cal(true);
exit(0);
}
return;
}
if(t - pre > 1)
{
for(int i = 0; i < 4; i++)
{
ch[++p[t]] = pp[i];
dfs(t, pre + 1);
ch[p[t]--] = 0;
}
}
dfs(t + 1, pre);
}
int main()
{
scanf("%d%d%d%d", &a[1], &a[2], &a[3], &a[4]);
do
{
//memset(ch, 0, sizeof ch);
ch[1] = a[1] + '0';
ch[6] = a[2] + '0';
ch[11] = a[3] + '0';
ch[16] = a[4] + '0';
p[1] = 1; p[2] = 6;
p[3] = 11; p[4] = 16;
//print();
dfs(2, 0);
}
while(std::next_permutation(a + 1, a + 5));
printf("No answer!\n");
return 0;
}