P2277 题解
yeshubo_qwq · · 题解
题意
求有几种方式算出
思路
大致思路:dfs 排列每种情况,再暴力枚举运算符号,最后判断是否算出
这里讲一下几个注意点:
1.注意判断实数计算的误差。
2.括号前面是减号、除号,加上括号要变号,因此加上括号后可能与枚举的符号不同。
3.判重可以将先将算式转为后缀表达式,再用状压将后缀表达式转成数,并用 map 去重。
#include<bits/stdc++.h>
using namespace std;
const double check=1e-6;//实数计算误差
int ans,v[5],pm[5],f[5],g[5];
map<int,int> mp;
double num(double x,double y,int z){//计算
switch(z){//z表示运算符:0加,1减,2乘,3除
case 0:return x+y; break;
case 1:return x-y; break;
case 2:return x*y; break;
case 3:return x/y; break;
}
}
double Abs(double p){//实数绝对值
return (p<0?-p:p);
}
int useful(int a,int b){//能不能加括号
//括号前面是减号、除号,加上括号要变号
if(a%2==1) return 1;
if(!a) return (b>1?1:0);
else return (b<2?1:0);
}
void mplus(int a1,int a2,int a3,int a4,int a5,int a6,int a7){//map+状压去重
int x=(a1|a2<<3|a3<<6|a4<<9|a5<<12|a6<<15|a7<<18);
if(++mp[x]==1)ans++;
}
int find(int x){//x是第几个
for(int i=1;i<=4;i++)
if(f[i]==x)return i;
}
void count(int a,int b,int c,int d){//暴力计算
for(int i=0;i<=3;i++)//i,j,k枚举符号
for(int j=0;j<=3;j++)
for(int k=0;k<=3;k++){
/* 5种添括号
(1,2,3,4)
((1,2),(3,4))
(1,(2,3,4))
((1,(2,3)),4)
(1,(2,(3,4)))*/
int u1=useful(k,j), u2=useful(j,i);
if( Abs((num( num( num(a,b,i) ,c,j),d,k) -24 ))<check)
mplus(pm[find(a)],pm[find(b)],(i+4),pm[find(c)],(j+4),pm[find(d)],(k+4));
if(u1==1&& Abs(num( num(a,b,i),num(c,d,j) , k) -24 )<check)
mplus(pm[find(a)],pm[find(b)],(i+4),pm[find(c)],pm[find(d)],(j+4),(k+4));
if(u1==1&& Abs(num(a,num( num(b,c,i),d,j),k) -24 )<check)
mplus(pm[find(a)],pm[find(b)],pm[find(c)],(i+4),pm[find(d)],(j+4),(k+4));
if(u2==1&& Abs(num(num(a, num(b,c,i) ,j),d,k) -24 )<check)
mplus(pm[find(a)],pm[find(b)],pm[find(c)],(i+4),(j+4),pm[find(d)],(k+4));
if(u1==1&&u2==1&& Abs(num(a, num(b,num(c,d,i),j),k)-24 )<check)
mplus(pm[find(a)],pm[find(b)],pm[find(c)],pm[find(d)],(i+4),(j+4),(k+4));
}
}
void dfs(int x){//dfs求排列
if(x>4){
count(g[1],g[2],g[3],g[4]);
return;
}
for(int i=1;i<=4;i++)
if(v[i]==0)
v[i]=1,g[x]=f[i],dfs(x+1),v[i]=0;
}
int main(){
for(int i=1;i<=4;i++)scanf("%d",&f[i]);
for(int i=1;i<=4;i++)
for(int j=1;j<=4;j++)
pm[i]=pm[i]+(f[i]<f[j]?1:0);//排第几,用于状压判重(最大0)
dfs(1);
printf("%d",ans);
}
}