题意:
给定n个筷子的长度,取k+8套筷子,每套有3个,长度分别为A,B,C。
求组成k+8套筷子(A-B)^2的和的最小值,输出这个最小值。
思路:
题目中所给的筷子长度是非降序排列的,所以最小的两个A和B一定是相邻的。
先不考虑筷子C,只要留着就行,即(n-j)> (k-i)*3 (加上等号就代表没有预留筷子C)
dp[i][j]表示从 j 个筷子中取 i 套筷子的最优值
对于第j根筷子(j >= i * 2)都有两种情况
①不做A,B筷, dp[i][j] = dp[i][j-1]
②做A,B筷, dp[i][j] = dp[i-1][j-2] + (l[j] - l[j-1]) * (l[j] - l[j-1])
题目所求就是dp[k+8][n]
代码如下:
#include<cstdio>
#include<cstring>
#include<string>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N = 5010;
#define INF 1<<30
int t, n, k;
int l[N], dp[1005][N]; //dp[i][j] 表示j根筷子能组成i组的最优解
int main()
{
scanf("%d",&t);
while(t--)
{
scanf("%d%d", &k, &n);
for(int i = 1; i <= n; i++)
{
scanf("%d", &l[i]);
}
memset(dp, 0, sizeof(dp));
k += 8;
for(int i = 1; i <= k; i++)
{
for(int j = 2 * i; j <= n; j++)
{
dp[i][j] = INF;
if(j > 2 * i)
dp[i][j] = dp[i][j - 1]; //不用这根筷子
if((n - j) > (k - i) * 3)
{
int tmp = dp[i-1][j-2] + (l[j] - l[j-1]) * (l[j] - l[j-1]); //用这根筷子
if(tmp < dp[i][j])
dp[i][j] = tmp;
}
}
}
printf("%d\n", dp[k][n]);
}
return 0;
}