洛谷 P1880 石子合併 區間dp
阿新 • • 發佈:2019-02-07
題目描述
在一個園形操場的四周擺放N堆石子,現要將石子有次序地合併成一堆.規定每次只能選相鄰的2堆合併成新的一堆,並將新的一堆的石子數,記為該次合併的得分。
試設計出1個演算法,計算出將N堆石子合併成1堆的最小得分和最大得分.
輸入輸出格式
輸入格式:資料的第1行試正整數N,1≤N≤100,表示有N堆石子.第2行有N個數,分別表示每堆石子的個數.
輸出格式:輸出共2行,第1行為最小得分,第2行為最大得分.
輸入輸出樣例
輸入樣例#1:4 4 5 9 4輸出樣例#1:
43 54
思路
定義狀態
maxdp(i, j)表示i到j的最大值
mindp(i, j)表示i到j的最小值
則狀態轉移方程為:
maxdp(i, j) = MAX{maxdp(i, k) + maxdp(k + 1, j) + sum(i, j) }
mindp(i, j) = MIN{mindp(i, k) + mindp(k + 1, j) + sum(i, j)}
ac程式碼
#include <iostream> #include <vector> #include <string> #include <algorithm> #include <cstdio> #include <cstring> #include <ctime> #include <cstdlib> #include <set> #include <map> #include <cctype> #include <list> #include <cmath> #include <bitset> #include <queue> #include <stack> #include <sstream> #include <functional> #include <cassert> using namespace std; #define tmax(a, b) if (b > a) a = b #define tmin(a, b) if (b < a) a = b char inc() { char _[10]; scanf("%s", _); return _[0]; } int ini() { int _; scanf("%d", &_); return _; } long long inll() { long long _; scanf("%I64d", &_); return _; } double ind() { double _; scanf("%lf", &_); return _; } string ins() { string _; cin >> _; return _; } int inl(char _[]) { if (!fgets(_, (int)1e8, stdin)) return -1; int i = strlen(_); if (_[i - 1] == '\n') _[--i] = 0; return i; } typedef pair<int, int> pii; typedef pair<char, char> pcc; typedef long long LL; const int inf = 0x3f3f3f3f; const LL lnf = 0x3f3f3f3f3f3f3f3f; const double pi = 3.14159265358979323846; const double eps = 1e-8; const int mod = 100007; const int maxn = 200+ 10; int n, a[maxn], prefix[maxn]; int maxdp[maxn][maxn], mindp[maxn][maxn]; int main() { int CAS = 0; //std::ios::sync_with_stdio(0); //std::cin.tie(0); #ifdef NIGHT_13 freopen("in.txt", "r", stdin); // freopen("out.txt", "w", stdout); int time_night_13 = clock(); #endif // NIGHT_13 scanf("%d", &n); for (int i = 0; i < n; ++i) { a[i] = a[i + n] = ini(); prefix[i] = prefix[i - 1] + a[i]; } for (int i = n; i < 2 * n; ++i) prefix[i] = prefix[i - 1] + a[i]; memset(mindp, 0x3f, sizeof mindp); for (int k = 0; k < n; ++k) { //len - 1 for (int i = 0; i + k < 2 * n; ++i) { //i: start, i + k: end if (k == 0) maxdp[i][i + k] = mindp[i][i + k] = 0; else if (k == 1) maxdp[i][i + k] = mindp[i][i + k] = a[i] + a[i + 1]; else for (int j = i; j < i + k; ++j) { //mid tmax(maxdp[i][i + k], maxdp[i][j] + maxdp[j + 1][i + k] + prefix[i + k] - prefix[i - 1]); tmin(mindp[i][i + k], mindp[i][j] + mindp[j + 1][i + k] + prefix[i + k] - prefix[i - 1]); } } } int maxans = -inf, minans = inf; for (int i = 0; i + n - 1 < 2 * n; ++i) { tmax(maxans, maxdp[i][i + n - 1]); tmin(minans, mindp[i][i + n - 1]); } printf("%d\n%d\n", minans, maxans); #ifdef NIGHT_13 fprintf(stderr, "\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n"); fprintf(stderr, "\t Time: %d ms", (int)clock() - time_night_13); fprintf(stderr, "\n...........................................\n\n"); #endif // NIGHT_13 return 0; }