P1115 最大子段和
阿新 • • 發佈:2022-04-15
一、暴力法
\(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;
}