1 条题解
-
0
#include<bits/stdc++.h> using namespace std; // [1] arr数组-存储每堆石子的数量(下标1~n);brr数组-前缀和数组,brr[i]表示前i堆石子的总数 int arr[110],brr[110]={}; // [2] dp[l][r]-合并区间[l, r]内的石子能得到的最小得分;dp_max[l][r]-合并区间[l, r]内的石子能得到的最大得分 int dp[110][110]; int dp_max[110][110]; int main(){ int n; cin>>n; // [3] 读取石子堆数n for(int i=1;i<=n;i++){ cin>>arr[i]; brr[i]=brr[i-1]+arr[i]; // [4] 计算前缀和:前i堆石子的总数 = 前i-1堆的和 + 当前堆的数量 } // 数组初始化 memset(dp, 0x3f, sizeof(dp)); // [5] 最小得分dp初始化为极大值(0x3f表示不可达,后续取最小值) memset(dp_max, 0, sizeof(dp_max)); // [6] 最大得分dp_max初始化为0 // 单堆石子无需合并,得分是0 for (int i = 1; i <= n; i++){ dp[i][i] = 0; dp_max[i][i] = 0; } // 区间DP核心循环:按区间长度从小到大计算(len为区间长度,从2到n) for(int len=2;len<=n;len++){ // 遍历所有长度为len的区间的左端点l for(int l=1;l+len-1<=n;l++){ int r=l+len-1; // [7] 计算当前区间的右端点r // 枚举分割点i,将区间[l, r]分为[l, i]和[i+1, r]两个子区间 for(int i=l;i<r;i++){ // 计算当前区间的石子总数(合并时的得分贡献) int sum = brr[r] - brr[l-1]; // 状态转移:合并区间[l, r]的得分 = 合并左子区间的得分 + 合并右子区间的得分 + 当前区间的石子总数 // 最小得分取所有分割方式中的最小值 dp[l][r] = min(dp[l][r], dp[l][i] + dp[i+1][r] + sum); // 最大得分取所有分割方式中的最大值 dp_max[l][r] = max(dp_max[l][r], dp_max[l][i] + dp_max[i+1][r] + sum); } } } // 输出合并所有石子(区间[1, n])的最小得分和最大得分 cout<<dp[1][n]<<endl<<dp_max[1][n]; return 0; }
- 1
信息
- ID
- 1347
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者