时间限制:1000MS 代码长度限制:10KB
提交次数:0 通过次数:0
题型: 编程题 语言: G++;GCC;VC;JAVA
给定n个石子,其重量分别为a1,a2,a3,…,an。
要求将其划分为m份,每一份的划分费用定义为这份石子中最大重量与最小重量差的平方。
总划分费用为m份划分费用之和。
现在对于给定的n个石子,求一种划分方案,使得总划分费用最小。
第一行两个正整数n和m,接下来一行有n个正整数,表示一个石子的重量ai。(1≤n, m, ai≤1000)
计算输出最小总划分费用。
注意:若一份只有一个石子,那么,这份石子中最大重量与最小重量的差的平方为0。
4 2
4 7 10 1
18
例如:
n=5, m=2
a[1…5] = 1 3 4 8 9
f(5,2)=Min{ f(4,1)+0; f(3,1)+1; f(2,1)+5^2 }=Min{49,10,29}=10
这5个石头分2堆的最优分法:(1 3 4)(8 9)
dp[n][m] = dp[n - k][m - 1] + (a[n] - a[n - k + 1]) * (a[n] - a[n - k + 1])
假设最后一份石头有 k 堆,则 dp[n][m] 为前 n - k 堆中挑选出 m - 1 份的得分,加上最后这一份的石头得分,得分为最后一堆减去第一堆的平方(因为已经升序排序,所以最大的在这一份最后,最小的一定在这一份开头)
更多注释可查看下方的完整代码中,有助于理解
#include
#include
#include
#include
/*
4 2
4 7 10 15 2
1 3 4 8 9
*/using namespace std;int a[1001];
int dp[1001][1001]; // 前 n 堆石头分成 m 份int main()
{int i, j, k, n, m;cin >> n >> m;for(i = 1; i <= n; i++) {cin >> a[i];}sort(a + 1, a + n + 1);memset(dp, 1e9, sizeof(dp));// 前 i 堆石头划分成1堆,只有一种分法,也就是全部放一起for(i = 1; i <= n; i++) {dp[i][1] = (a[i] - a[1]) * (a[i] - a[1]);}for(i = 2; i <= n; i++) {for(j = 2; j <= m; j++) {// 划分后,最后一堆石头有 k 个,例如如果5堆石头划分成2份,最后一堆石头可以有1,2,3,4堆int minNum = 1e9;for(k = 1; k <= i - j + 1; k++) {minNum = min(minNum, dp[i - k][j - 1] + (a[i] - a[i - k + 1]) * (a[i] - a[i - k + 1]));//cout << "i=" << i << " j=" << j << " k=" << k << " dp[" << i-k << "][" << j - 1 << "]=" << dp[i - k][j - 1] << " a=" << a[i] - a[i - k + 1] << endl;}dp[i][j] = minNum;//cout << "dp[" << i << "][" << j << "]=" << dp[i][j] << endl;}}cout << dp[n][m] << endl;return 0;
}
对我感兴趣的小伙伴可查看以下链接