Problem - 1045 (sdnu.edu.cn)石子合并1
有n堆石子排成一行,每次选择相邻的两堆石子,将其合并为一堆,记录该次合并的得分为两堆石子个数之和。已知每堆石子的石子个数,求当所有石子合并为一堆时,最小的总得分。
第一行一个整数n(1 <= n <= 200),表示石子堆数;
第二行n个整数a(1 <= a <= 100),表示每堆石子的个数。
#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
const int N = 210;
int f[N][N], sum[N];
int main(){
//std::ios::sync_with_stdio(false);
//std::cin.tie(nullptr);
int n;
cin >> n;
memset(f, 0x3f, sizeof f);//初始化呢,脑子呢?!
for (int i = 1, x; i <= n; i ++ ) {
cin >> x;
sum[i] = sum[i - 1] + x;
f[i][i] = 0;
}
for (int len = 2; len <= n; len ++ ) {
for (int l = 1; l + len - 1 <= n; l ++ ) {
int r = l + len - 1;
for (int k = l; k < r; k ++ ) { // 左闭右开
f[l][r] = min(f[l][r], f[l][k] + f[k + 1][r]); //[l,k],[k + 1,r]这都是规定
}
f[l][r] += sum[r] - sum[l - 1];
}
}
cout << f[1][n] << '\n';
return 0;
}
Problem - 1048 (sdnu.edu.cn)石子合并2
有n堆石子排成一圈,每次选择相邻的两堆石子,将其合并为一堆,记录该次合并的得分为两堆石子个数之和。已知每堆石子的石子个数,求当所有石子合并为一堆时,最小的总得分。
第一行一个整数n(1 <= n <= 200),表示石子堆数;
第二行n个整数a(1 <= a <= 100),表示每堆石子的个数,这些石子首尾相接排成一圈。
#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
const int N = 210;
int f[N][N], sum[N], a[N];
int main(){
//std::ios::sync_with_stdio(false);
//std::cin.tie(nullptr);
int n;
cin >> n;
memset(f, 0x3f, sizeof f);
for (int i = 1; i <= n; i ++ ) {
cin >> a[i];
sum[i] = sum[i - 1] + a[i];
f[i][i] = 0;
}
// 还是要求前缀和,查询区间和为多少
for (int i = n + 1; i <= 2 * n; i ++ ) {
f[i][i] = 0;
sum[i] = sum[i - 1] + a[i % n];
}
for (int len = 2; len <= n; len ++ ) {
for (int l = 1; l + len - 1 <= 2 * n; l ++ ) {
int r = l + len - 1;
for (int k = l; k < r; k ++ ) {
f[l][r] = min(f[l][r], f[l][k] + f[k + 1][r]);
}
f[l][r] += sum[r] - sum[l - 1];
}
}
int ans = 0x3f3f3f3f;
for (int i = 1; i <= n; i ++ ) {//原来是一个区间,现在变成n个区间
ans = min(ans, f[i][i + n - 1]);
}
cout << ans << '\n';
return 0;
}
Problem - 1013 (sdnu.edu.cn)1013.石子合并简化版
有n堆石子,每次从中抽取两堆进行合并,合并后的石子数记做权,并把合并后的石子堆当做新的一堆放回,重新随机抽取两堆石子,重复上面的操作,直到所有石子合并成一堆,则每次合并的和的总和是多少?
第一行:石子的堆数n(1 <= n <= 10000)。
第二行:每堆石子的石子数a[i](1 <= a[i] <= 10000)。
每次合并的权的最大总和(由于最后的结果较大,请对最终的结果mod1000000007)
贪心
每次合并两个最大的,过