HDU4192Guess the Numbers逆波兰表示法+全排列

题目在这里》

题意:给你一个中序表达式,由(、)、+、-、*以及a-z的小写字母组成,其中有n个不同的小写字母表示n个未知数,再给n个数分别表示这n个未知数的值,再给一个数m,求判断是否能够将这n个数分别赋值给这n个未知数代入表达式所算出的值恰为m。

思路:由于题目给的是中序表达式,不方便计算,所以要先将中序表达式转化为逆波兰式。

先来复习一下将一个中序表达式转化为逆波兰式的算法:

1:准备2个栈,一个存符号(记为栈1),另一个存变量(记为栈2);

2:依次读取中序表达式,

     (1)如果当前字符是‘(’,直接进栈1;

     (2)如果当前字符是‘)’,将符号栈栈顶元素依次弹入栈2,直至符号栈栈顶为‘(’,此时‘(’出栈;

     (3)如果是变量,直接进栈2;

     (4)如果是运算符

                 1》如果符号栈栈顶运算符优先级小于当前运算符优先级,或者符号栈为空或者符号栈栈顶元素为‘(’,直接进栈;

                2》如果符号栈栈顶运算符优先级大于等于当前运算符优先级,将符号栈栈顶元素依次弹入栈2,直到符号栈栈顶运算符优先级小于当前运算符优先级,当前运算符进栈1;

好了,将中序表达式转化为逆波兰式后就好办了,直接求n个数的全排列,然后用逆波兰式轻松求出表达式的值就简单多了,详情请见代码:

#include <iostream>
#include<cstdio>
#include<cstring>

using namespace std;

char stack1[20],stack2[20],str[20];
int top1,top2;
int n,m;
int v[10];
int flag;
int fv[10];
int cur[10];

int cal()
{
    int i,j;
    int lcm[10],len = 0;
    j = 0;
    for(i = 0;i < top2;i ++)
    {
        if(islower(stack2[i]))
            lcm[len ++] = cur[j ++];
        else
        {
            len --;
            switch(stack2[i])
            {
                case '+':lcm[len - 1] += lcm[len];
                break;
                case '-':lcm[len - 1] -= lcm[len];
                break;
                case '*':lcm[len - 1] *= lcm[len];
            }
        }
    }
    return lcm[0];
}

void dfs(int i,int cnt)
{
    if(flag)
        return;
    if(cnt == n - 1)
    {
        if(cal() == m)
        {
            flag = 1;
        }
        return;
    }
    int j;
    for(j = 0;j < n;j ++)
    {
        if(!fv[j])
        {
            fv[j] = 1;
            cur[cnt + 1] = v[j];
            dfs(j,cnt + 1);
            fv[j] = 0;
        }
    }
}

int main()
{
    int i;
    char c;
    while(scanf("%d",&n),n)
    {
        for(i = 0;i < n;i ++)
            scanf("%d",&v[i]);
        scanf("%d",&m);
        top1 = top2 = 0;
        scanf("%s",str);
        for(i = 0;i < strlen(str);i ++)
        {
            switch(str[i])
            {
                case '(':stack1[top1 ++] = str[i];
                break;
                case ')':while(stack1[top1 - 1] != '(')
                               stack2[top2 ++] = stack1[--top1];
                        top1 --;
                        break;
                case '*':if(top1 == 0 || stack1[top1 - 1] == '+'
                    || stack1[top1 - 1] == '-' || stack1[top1 - 1] == '(')
                            stack1[top1 ++] = '*';
                        else
                        {
                            while(stack1[top1 - 1] == '*')
                                stack2[top2 ++] = stack1[--top1];
                        }
                        break;
                case '+':
                case '-':if(stack1[top1 - 1] == '(' || top1 == 0)
                            stack1[top1 ++] = str[i];
                        else
                        {
                            while(stack1[top1 - 1] == '*')//stack1[top1 - 1] == '+' || stack1[top1 - 1] == '-')//之前写的有问题,竟然能过。。。
                                stack2[top2 ++] = stack1[--top1];
                        }
                        break;
                default:stack2[top2 ++] = str[i];
            }
        }
        flag = 0;
        for(i = 0;i < n;i ++)
        {
            memset(fv,0,sizeof(fv));
            fv[i] = 1;
            cur[0] = v[i];
            dfs(i,0);
        }
        if(flag)
            printf("YES\n");
        else
            printf("NO\n");
        /*for(i = 0;i < top2;i ++)
            printf("%c",stack2[i]);
        printf("\n");*/
    }
    return 0;
}
//62MS	324K


      

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值