一道貪心:加括號使算式的值最大
阿新 • • 發佈:2018-11-10
問題描述
給定一個算術表示式形如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; }