poj--1100 Dreisam Equations(dfs)

Problem Link

题解

在等式中重新放置 + - * 以便构造一个有效的等式。

对于每个可以放置运算符的位置,都有三种选择,因此解空间是一棵完全三叉树,回溯搜索 O(3n)

需要注意存在冗余括号的情况。

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

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

const int maxn = 100;
char a[maxn];   // 原始的等式数据
int b[maxn];    // 伪表达式
int best[maxn]; // 存储答案
int op[maxn];   // 运算符在数组b中的位置
int bn;         // 数组b的项数
int iLeft;      // 等号左边的数
int possible;   // 是否有解
int apos, bpos, opos;   // 位置指针

// 跳过空格
void skipSpace(){
    while(a[apos] && a[apos] == ' ') apos++;
}

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 dep){
    if(possible) return;
    // 所有的运算符构造完毕,判断等式是否成立
    if(dep == opos){
        bpos = 0;
        int iRight = compute();
        if(iRight == iLeft){
            possible = 1;
            for(int i = 0; i < bn; ++i) best[i] = b[i];
        }
        return;
    }

    // Hint: 这里有顺序要求
    b[op[dep]] = ADD; dfs(dep + 1);
    b[op[dep]] = SUB; dfs(dep + 1);
    b[op[dep]] = MUL; dfs(dep + 1);

}

int main(){
#ifndef ONLINE_JUDGE
freopen("data.in", "r", stdin);
#endif // ONLINE_JUDGE

    int _ = 1;
    while(gets(a) && strchr(a, '=')){
        possible = 0;
        for(int i = 0; i < maxn; ++i) b[i] = NONE;
        apos = 0;
        sscanf(a, "%d", &iLeft);    // '='左边的数
        while(a[apos] && isdigit(a[apos])) apos++;
        skipSpace();
        apos++; //跳过 '='
        // 处理'='右边
        bn = 0;
        opos = 0;
        while(skipSpace(), a[apos]){
            if(a[apos] == '('){ // 左括号
                b[bn++] = LEFT;
                apos++;
                continue;
            }
            if(a[apos] == ')'){ // 右括号
                b[bn++] = RIGHT;
                apos++;
            }else{
                sscanf(a + apos, "%d", &b[bn++]);   // 读取数字
                while(a[apos] && isdigit(a[apos])) apos++;
            }
            skipSpace();
            // 如果不是结尾和')',则有一个运算符
            if(a[apos] && a[apos] != ')'){
                op[opos++] = bn;
                b[bn++] = OP;
            }
        }

        dfs(0);
        printf("Equation #%d:\n", _++);
        if(!possible || !bn){
            printf("Impossible\n");
        }else if(bn == 1 && iLeft == b[0]){
            printf("%d=%d\n", iLeft, iLeft);
        }else{
            printf("%d=", iLeft);
            for(int i = 0; i < bn; ++i){
                switch(best[i]){
                    case ADD:   printf("+"); break;
                    case SUB:   printf("-"); break;
                    case MUL:   printf("*"); break;
                    case LEFT:  printf("("); break;
                    case RIGHT: printf(")"); break;
                    default :   printf("%d", b[i]); break;
                }
            }
            printf("\n");
        }
        printf("\n");
    }

    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值