这道题的话利用了暴力深搜,尽管给了20S,但是这样还会超时,所以就需要利用回溯进行减枝,因为是DFS,所以用一个数组vis[i][j]记录是否在状态i时候取到过j值,如果取到过的话,那么直接回溯(往后搜索已经没有意义了,之前到达这个状态的时候是无法得到结果的)
还有需要注意的地方就是题目的要求,每一步的结构都在(-32000,32000)之间,所以需要一步判断,如果在这个范围外直接回溯
最后一点就是由于包含了除法,所以记得要考虑除数为0的情况,否则会RE
网上还有人利用DP思想做的,不过我还没学到这个专题,所以先不做过多的分析了
减枝前后的时间从TEL减到了0.48s,可以看出正确的减枝对程序优化的巨大作用
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define N 100 + 10
#define MAXD 100000
int n,m,ok;
int array[N];
char oper[N];
int vis[N][MAXD];
void solve(int u,int sum){
if(ok) return ;
if(sum > 32000 || sum < -32000) return ;
if(u == n && sum == m){
ok = 1;
return ;
}
if(vis[u][sum + 32000]) return ;
vis[u][sum + 32000] = 1;
if(u == n) return ;
oper[u] = '+'; solve(u + 1, sum + array[u]);
if(ok) return ;
oper[u] = '-'; solve(u + 1, sum - array[u]);
if(ok) return ;
oper[u] = '*'; solve(u + 1, sum * array[u]);
if(ok) return ;
if(array[u] != 0){
oper[u] = '/'; solve(u + 1, sum / array[u]);
if(ok) return ;
}
}
int main(){
int T;
scanf("%d",&T);
for(int Case = 1; Case <= T; Case ++){
ok = 0;
memset(vis,0,sizeof(vis));
scanf("%d",&n);
for(int i = 0; i < n ; i++)
scanf("%d",&array[i]);
scanf("%d",&m);
solve(1,array[0]);
if(ok)
for(int i = 0; i < n ; i++){
printf("%d",array[i]);
if(i < n - 1) printf("%c",oper[i + 1]);
if(i == n - 1) printf("=%d",m);
}
else printf("NO EXPRESSION");
printf("\n");
}
return 0;
}