10400 -Game Show Math

这道题的话利用了暴力深搜,尽管给了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;
}


你可能感兴趣的:(10400 -Game Show Math)