一道贪心:加括号使算式的值最大

问题描述

给定一个算术表达式形如1+3-5-4+6,表达式中的运算数全部都是正数,运算符全部是加号或者减号。
现在可以给算术表达式加任意多的括号,使得表达式的值最大。
如对于1+3-6-9+4-5-7+8,可以1+3-(6-9)+4-(5-7)+8,最优的方案是1+3-(6-9+4-5-7)+8

数据格式

T 例子个数
n1 第一个例子的运算数个数
1+3-6-9+4-5-7+8 算数表达式
n2
......

输出一个数字,表示表达式的最大值。
数据范围:运算数个数为1e5。

解析

  • 最优答案中,括号只加在减号前面
  • 最优答案中,若干个加号之间不加括号,例如3-4+5+6+7-8,其中5,6,7之间肯定没有括号
  • 最优答案中,括号肯定不会嵌套
  • 最优答案中,形如-a+b-c,如果c<b,那么-(a)+b-(c 比-(a+b-c 结果要好。

贪心的原则就是,既然无论如何都要给右面留下左括号,那么左括号的位置必然是最优的。

代码

#include<iostream>
using namespace std;
const int maxn = 1e5 + 7;
typedef  long long ll;
int a[maxn];
char op[maxn];
int m;
int find(int ind) {
    for (int i = ind; i < m; i++) {
        if ( op[i] == '+' &&(i >= m - 1 || a[i + 1] < a[i])) {
            return i-1;
        }
    }
    return m - 1;
}
ll sum_range(int f, int t) {
    ll s = 0;
    for (int i = f; i <= t; i++) {
        int value = (op[i] == '+' ? 1 : -1)*a[i];
        s -= value; 
    }
    return s;
}
ll solve() {
    //压缩正号
    int i = 0;
    for (int j = 1; j < m; j++) {
        if (op[j] == '+') {
            if (op[i] == '+')
                a[i] += a[j];
            else {
                i++;
                op[i] = '+';
                a[i] = a[j];
            }
        }
        else {
            i++;
            op[i] = '-';
            a[i] = a[j];
        }
    }
    m = i + 1; 
    ll s = 0;
    //如果我后面的负数比我大,我就要牺牲
    for (int i = 0; i < m; i++) { 
        if (op[i] == '-') {
            int j = find(i);
            s += -a[i]+sum_range(i+1, j); 
            i = j;
        }
        else {
            s += a[i];
        } 
    }
    return s;
}
int main() {
    freopen("in.txt", "r", stdin);
    int n;
    cin >> n;
    for (int i = 0; i < n; i++) {
        cin >> m;
        op[0] = '+';
        for (int j = 0; j < m; j++) {
            if (j > 0) {
                cin >> op[j];
            }
            cin >> a[j];
        }
        cout << solve() << endl;
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/weiyinfu/p/9818616.html