ZOJ-1145-Dreisam Equations

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

*/

 

你可能感兴趣的:(ZOJ)