/* 在一个圆形操场的四周摆放 N 堆石子,现要将石子有次序地合并成一堆, 规定每次只能选相邻的 2 堆合并成新的一堆,并将新的一堆的石子数,记为该次合并的得分。 试设计出一个算法,计算出将 N 堆石子合并成 1 堆的最小得分和最大得分。 洛谷题号:P1880 https://www.luogu.com.cn/problem/P1880 */ /* 状态转移方程 dp[i][j]:表示将第i~j对石子合并为一堆石子的最小得分 dp[i][j]= min( dp[i][k] + dp[k+1][j] ) (i <= k < j) k是某个分界点,左边一堆 i~k 的最小得分就是dp[i][k],右边一堆 k+1~j 的最小得分是dp[k+1][j] 状态转移方程需要结合分析图来看,分析图参考同目录下的 '11 石子合并问题.png' */ // 这里先用递归方式来实现上述动态转移方程 #include <cstdio> #include <iostream> #include <cmath> using namespace std; int a[100] = {0}; //前缀和,可以简化第1堆石子的总分数求和 int dp[100][100] = {0}; int stoneMerge(int l, int r) { //边界值 if(l == r) return 0; //只有一堆的情况无需再分堆 if(dp[l][r]>0) return dp[l][r]; int ans = INT_MIN; for (int k = l; k < r; k++) { ans = max(ans, stoneMerge(l, k) + stoneMerge(k + 1, r)); } ans += (a[r] - a[l - 1]); dp[l][r] = ans; return dp[l][r]; } //l表示起始堆好,r表示末尾堆号 /*测试数据 7 13 7 8 16 21 4 18 */ int main(void) { int n = 0;//输入的整数的个数 cin >> n; for (int i = 1; i <= n; i++) { cin >> a[i]; a[i] += a[i - 1]; } int minScore = stoneMerge(1, n); cout << "\n" << minScore; return 0; }
浙公网安备 33010602011771号