http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=1145

题目大意:

一种只有三种运算符的运算:加减乘,而且运算没有优先规则:他们知识严格的将没想数据从左边计算到右边。例如:3+3*5,他们的计算结果是30,而不是18

编程要求:

         对于输入的等式,将等号右边的数据之间加上运算符,使其计算结果为等号左边的数,然后输出添加运算符后的等式,如果不能求得满足要求等式,输出“Impossible”,每组数据后输出一个空行。

算法分析:

         对于此题,要解决的主要问题有:1、构造表达式 2、求解构造的表达式的值

         由于此题求解过程中需要多次遍历表达式,所以如果将表达式存储起来程序运行起来就回快很多,具体就是转化为伪表达式,将括号进行整数化标记,按照整数数据存储起来,并将需要插入运算符的位置记录下来,这样每次只需在需要插入运算符的位置上dfs插入运算符,然后递归求表达式的值就行了。

         具体:用数组b[]存放伪表达式,op[]存放运算符在数组中的位置,ansx[]存放运算符

View Code
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;

#define LEFT -1        //左括号
#define    RIGHT -2    //右括号
#define    MUL    -3        //*号
#define    ADD    -4        //+号
#define    SUB -5        //-号
#define    OP    -6        //有运算符
#define NONE -10

int ans,flag;
int b[100],    //伪表达式
    op[50],    //运算符在数组b中的位置
    bn,        //数组b的项数
    ansx[15],//答案,存放的为运算符
    ipos,bpos,opos;
char str[100];    
char pop[] = " ()*+-?";

int compute();

int bracket()
{
    int sum;
    if(b[bpos] == LEFT)
    {
        ++ bpos;    //跳过左括号
        sum = compute();    //计算括号里面的值
        ++ bpos;    //跳过右括号
    }
    else
        sum = b[bpos++];    //没有括号
    return sum;
}

int compute()    //求解表达式的值
{
    int sum = bracket();    //取出第一个数
    while(b[bpos] == MUL || b[bpos] == ADD || b[bpos] ==  SUB)
    {
        int operation = b[bpos++];    //取出运算符
        int ret = bracket();    //取出下一个数
        switch(operation)
        {
        case MUL:    sum *= ret;    break;
        case ADD:    sum += ret;    break;
        case SUB:    sum -= ret;    break;
        }
    }
    return sum;
}

void dfs(int t)    //dfs插入运算符,求解表达式,
{
    if(flag)    return ;
    int i;
    if(t == opos)    //运算符插入完毕,计算表达式的值
    {
        bpos = 0;
        int tmp = compute();    //计算右边等式的值
        if(tmp == ans)
        {
            flag = 1;
            for(i = 0; i < bn; ++ i)
                ansx[i] = b[i];
        }
        return ;
    }
    b[op[t]] = MUL;    dfs(t+1);
    b[op[t]] = ADD;    dfs(t+1);
    b[op[t]] = SUB;    dfs(t+1);
}

void print(int q[])    //打印表达式
{
    printf("%d=",ans);
    int i;
    for(i = 0; i < bn; ++ i)
    {
        if(q[i] >= -6 && q[i] <= -1)
            putchar(pop[-q[i]]);
        else
            printf("%d",q[i]);
    }
}

void space()    //跳过空格
{
    while(str[ipos] && str[ipos] == ' ')
        ++ ipos;
}

int main()
{
    int test = 1;
    while(gets(str) && strchr(str,'=') && strcmp(str,"0") != 0)
    {
        for(int i = 0; i < 100; ++ i)
            b[i] = NONE;
        sscanf(str,"%d[^ =]",&ans);
        for(ipos = 0; str[ipos] != '='; ++ ipos);
        ++ ipos;        
        bn = 0;    opos = 0;
        while(space(),str[ipos])    //转化为伪表达式
        {
            if(str[ipos] == '(')    //左右括号
            {
                b[bn++] = LEFT,++ ipos;
                continue;
            }
            else if(str[ipos] == ')')
                b[bn++] = RIGHT,++ ipos;
            else
            {
                sscanf(str + ipos,"%d[^ ()]",&b[bn++]);    //保存整数数据
                while(str[ipos] && isdigit(str[ipos])) ++ipos;
            }
            space();
            if(str[ipos] && str[ipos] != ')')    //如果不是结尾和‘)’,则有一个运算符
            {
                op[opos++] = bn;    //记录运算符的位置
                b[bn++] = OP;
            }
        }
        flag = 0;
        dfs(0);
        printf("Equation #%d:\n",test ++);
        if(!flag)
            printf("Impossible");
        else
        {
            print(ansx);
        }
        printf("\n\n");
    }
    return 0;
}
/*
18 = 7 (5 3) 2
30 = 3 3 5
18 = 3 3 5
5 = 3 3
12 = 2 2 2 2    2 2
*/

 

posted on 2012-09-02 22:24  pcoda  阅读(713)  评论(0编辑  收藏  举报