计蒜客 表达式 (递归)


**链接 : ** Here!

**思路 : **

  • 这里采用一种非常风骚的写法, 对于求解表达式来说, 普通的做法就是用栈, 但是还可以利用递归来解决, 其实思考一下, 递归也是调用的系统栈, 所以说本质上并没有什么区别.

  • 首先, 设置优先级

    • "(", ")" 的优先级最高, 设置为100
    • "^" 的优先级次之, 设置为3
    • "*", "/" 的优先级再次之, 设置为2
    • "+", "-" 的优先级最低, 设置为1
  • 当传入一个字符串后, 给字符串中的所有运算符标记优先级等级, 然后选出来优先级最低的运算符, 因为优先级最低的运算符一定是最后计算, 因此就可以将一个表达式拆分成两个子表达式, 因此这就将大问题转化为等价的小问题, 递归解决即可

  • 这道题目中有变量 $a$ , 那么这该如何处理呢 ? 我们可以将 $a$ 替换为其他数字, 只要最后计算的结果相同就可以认为两个表达式是等价的,

  • 注意 :
    - 幂运算的数值可能非常大, 因此需要进行取模, 这里的 $MOD = 1e9 + 7$, 如果遇到乘法的话很可能超出 $int$ 的范围, 因此用 $longlong $ 来存储计算值.
    - 选用什么值来替换 $a$ 也是需要注意的一个地方.


代码 :

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

#define INF 1e9
typedef long long ll;
const int MOD = 1e9 + 7;

ll quick_pow(ll a, ll b) {
    ll ret = 1;
    while (b) {
        if (b & 1) ret = ret * a % MOD;
        a = a * a % MOD;
        b >>= 1;
    }
    return ret % MOD;
}

// [st, ed)
ll cal_num(char *str, int st, int ed, int a) {
    int priority = 0;
    int opt_num = 0;
    int cur_priority = 0, min_priority = INF, min_pos = -1;
    for (int i = st ; i < ed ; ++i) {
        if (str[i] == '(') {priority += 100; continue;}
        else if (str[i] == ')') {priority -= 100; continue;}
        else if (str[i] == '+') cur_priority = priority + 1;
        else if (str[i] == '-') cur_priority = priority + 1;
        else if (str[i] == '*') cur_priority = priority + 2;
        else if (str[i] == '^') cur_priority = priority + 3;
        else continue;
        ++opt_num;
        if (cur_priority <= min_priority) {
            min_priority = cur_priority;
            min_pos = i;
        }
    }
    if (opt_num == 0) {
        ll temp = 0;
        for (int i = st ; i < ed ; ++i) {
            if (str[i] == 'a') return a;
            if (str[i] < '0' || str[i] > '9') continue;
            temp = temp * 10 + (str[i] - '0');
        }
        return temp % MOD;
    }
    ll ta = cal_num(str, st, min_pos, a);
    ll tb = cal_num(str, min_pos + 1, ed, a);
    switch (str[min_pos]) {
        case '+' :
            return (ta + tb) % MOD;
        case '-' :
            return (ta - tb + MOD) % MOD;
        case '*' :
            return (ta * tb) % MOD;
        case '^' :
            return quick_pow(ta, tb);
    }
    return 0;
}

#define MAX_RANGE 5
int main() {
    // char s[100] =  "((1+2)*3) ^ a";
    // printf("%d\n", cal_num(s, 0, strlen(s), 2));
    int rand_num[5] = {1, 2, 3, 4, 5};
    int n;
    char st[100], ed[100][100];
    while (scanf("%[^\n]s", st) != EOF) {
        scanf("%d", &n);
        for (int i = 0 ; i < n ; ++i) {
            getchar();
            scanf("%[^\n]s", ed[i]);
        }
        int vis[30] = {0}; // vis[i] = 0代表成功通过测试
        for (int i = 0 ; i < MAX_RANGE ; ++i) {
            int std_value = cal_num(st, 0, strlen(st), rand_num[i]);
            for (int j = 0 ; j < n ; ++j) {
                if (vis[j]) continue;
                int temp_value = cal_num(ed[j], 0, strlen(ed[j]), rand_num[i]);
                if (temp_value != std_value) {
                    vis[j] = 1;
                }
            }
        }
        for (int i = 0 ; i < n ; ++i) {
            if (vis[i]) continue;
            printf("%c", i + 'A');
        }
        printf("\n");
        getchar();
    }
    return 0;
}
posted @ 2017-11-23 13:29  ojnQ  阅读(291)  评论(0编辑  收藏  举报