UVa 817:According to Bartjens(DFS)

该博客介绍了如何解决UVa 817题目的算法,即根据输入的数字串构造使结果为2000的表达式。通过深度优先搜索(DFS)的方法,枚举插入加号、减号和乘号的数量,并使用栈来计算表达式的值。题目要求不包含前导零,遵循运算优先级,并在有多解的情况下按字典序输出。博客中提到代码实现并指出题目可能存在的歧义。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接:https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=842&page=show_problem&problem=758

题意:输入一个以等号结尾。前面只包含数字的表达式,插入一些加号、减号和乘号,使得运算结果等于2000.表达式里的整数不能有前导零(例如,0100和000都是非法的),运算符都是二元的(例如,2*-100*-10+0=是非法的),并且符合通常的运算优先级法则。输入数字个数不超过9。如果有多解按照字典序从小到大输出:如果无解,输出IMPOSSIBLE。例如,2100100=有3组解,按照字典序依次为2*100*10+0=、2*100*10-0=和2100-100=。(本段摘自《算法竞赛入门经典(第2版)》)

分析:
枚举插入运算符的个数,进行DFS即可。计算表达式的值直接用两个栈解决。需要注意的是,貌似题目并没有要求按字典序输出,还有就是至少要插入一个运算符。

代码:

#include <iostream>
#include <algorithm>
#include <fstream>
#include <string>
#include <cstring>
#include <vector>
#include <queue>
#include <cmath>
#include <cctype>
#include <stack>
#include <set>

using namespace std;

const int maxn = 20 + 5;

const char op[] = {"+-*"};

int C, l;
string s;
set< string > ans;

int cmp(char x, char y)
{
    if ((x == '-' || x == '+') && (y == '*'))
        return -1;
    return 1;
}

int calc(int x, int y, char op)
{
    switch(op)
    {
        case '+':
            return x + y;
        case '-':
            return x - y;
        case '*':
            return x * y;
    }
}

void update(const string& ss)
{
    stack< int > num;
    stack< char > opp;
    int len = ss.size();
    for (int i = 0; i < len; ++i)
    {
        int tmp = 0, pos = i;
        while (pos < len && isdigit(ss[pos]))
        {
            tmp = tmp * 10 + ss[pos] - '0';
            ++pos;
        }
        if (pos - i > 1 && ss[i] == '0')
            return;
        num.push(tmp);
        if (pos < len)
        {
            if (opp.size() == 0)
                opp.push(ss[pos]);
            else
            {
                if (cmp(opp.top(), ss[pos]) < 0)
                    opp.push(ss[pos]);
                else
                {
                    while (!opp.empty() && cmp(opp.top(), ss[pos]) >= 0)
                    {
                        int yy = num.top();
                        num.pop();
                        int xx = num.top();
                        num.pop();
                        char OP = opp.top();
                        opp.pop();
                        num.push(calc(xx, yy, OP));
                    }
                    opp.push(ss[pos]);
                }
            }
        }
        i = pos;
    }
    while (!opp.empty())
    {
        int yy = num.top();
        num.pop();
        int xx = num.top();
        num.pop();
        char OP = opp.top();
        opp.pop();
        num.push(calc(xx, yy, OP));
    }
    if (num.top() == 2000)
        ans.insert(ss);
}

void DFS(int pos, int deep, int limit, string ss)
{
    if (deep == limit)
    {
        update(ss);
        return;
    }
    int len = ss.size();
    if (len - pos - 1 < limit - deep)
        return;
    for (int i = pos + 1; i < len; ++i)
    {
        for (int j = 0; j < 3; ++j)
        {
            string tmp = ss;
            tmp.insert(i, 1, op[j]);
            DFS(i + 1, deep + 1, limit, tmp);
        }
    }
}

int main()
{
    while (cin >> s, s != "=")
    {
        ans.clear();
        s = s.substr(0, s.size() - 1);
        l = s.size();
        for (int maxd = 1; maxd < l; ++maxd)
            DFS(0, 0, maxd, s);
        printf("Problem %d\n", ++C);
        if (ans.size())
        {
            for (set< string >::iterator it = ans.begin(); it != ans.end(); ++it)
                cout << "  " << *it << "=\n";
        }
        else
            printf("  IMPOSSIBLE\n");
    }
    return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值