1. 程式人生 > 其它 >P1115 最大子段和

P1115 最大子段和

題目傳送門

一、暴力法

\(5\) 個測試點,全部\(TLE\)

#include <bits/stdc++.h>
using namespace std;
const int N = 200010;
const int INF = 0x3f3f3f3f;
int res = -INF;
int a[N];
int n;
int main() {
    cin >> n;
    for (int i = 1; i <= n; i++) cin >> a[i];
    for (int i = 1; i <= n; i++)       //列舉起點
        for (int j = i; j <= n; j++) { //列舉終點
            int sum = 0;
            for (int k = i; k <= j; k++) sum += a[k]; //區間內的和
            res = max(res, sum);
        }
    cout << res << endl;
    return 0;
}

二、字首和

\(5\) 個測試點,\(3\)\(TLE\)

#include <bits/stdc++.h>
using namespace std;
const int N = 200010;
const int INF = 0x3f3f3f3f;
int n, a[N], res = -INF;
int sum[N];
int main() {
    cin >> n;
    for (int i = 1; i <= n; i++) {
        cin >> a[i];                //輸入
        sum[i] = sum[i - 1] + a[i]; //記錄字首和
    }
    for (int i = 1; i <= n; i++)
        for (int j = i; j <= n; j++)
            res = max(res, sum[j] - sum[i - 1]);

    cout << res << endl;
    return 0;
}

三、分治法

\(AC\)掉本題

#include <bits/stdc++.h>
using namespace std;
const int INF = 0x3f3f3f3f;
const int N = 200010;
int n;
int a[N];
//分治函式
int rec(int l, int r) {
    //遞迴的出口
    if (l == r) return a[l]; // l=r時,直接返回該位置的值
    int mid = (l + r) >> 1;  //中間點
    // [l..mid]區間內包含mid的最大字尾和
    int sum = 0, lmax = -INF, rmax = -INF;
    for (int i = mid; i >= l; i--) sum += a[i], lmax = max(lmax, sum);
    // [mid+1..r]區間內包含(mid+1)的最大字首和
    sum = 0;
    for (int i = mid + 1; i <= r; i++) sum += a[i], rmax = max(rmax, sum);
    //三種可能取最大值
    return max(max(rec(l, mid), rec(mid + 1, r)), lmax + rmax);
}
int main() {
    cin >> n;
    for (int i = 1; i <= n; i++) cin >> a[i];
    printf("%d", rec(1, n)); //在範圍1~n之間求最大子段和
    return 0;
}

四、動態規劃法

\(AC掉本題\)

#include <bits/stdc++.h>
using namespace std;
const int N = 200010;
const int INF = 0x3f3f3f3f;
int n, a[N], f[N], res = -INF;
// 定義f[i]為從1開始,到i結束的所有數字中的最大子段和
// 從邊界開始考慮,如果f[1]=a[1];
// f[2] =max(a[2],a[2]+f[1])
// 推廣通用公式: f[i]=max(f[i-1]+a[i],a[i])
int main() {
    cin >> n;
    for (int i = 1; i <= n; i++) {
        cin >> a[i];                       //輸入
        f[i] = max(f[i - 1] + a[i], a[i]); // DP
        res = max(res, f[i]);              //取最大值也同時進行,節約時間
    }
    cout << res << endl;
    return 0;
}

五、線段樹