题目描述
A先生有很多双筷子。确切的说应该是很多根,因为筷子的长度不一,很难判断出哪两根是一双的。这天,A先生家里来了K个客人,A先生留下他们吃晚饭。加上A先生,A夫人和他们的孩子小A,共K+3个人。每人需要用一双筷子。A先生只好清理了一下筷子,共N根,长度为T1,T2,T3,......,TN。现在他想用这些筷子组合成K+3双,使每双的筷子长度差的平方和最小。(怎么不是和最小??这要去问A先生了,呵呵)
输入格式
两行:
第一行为两个用空格隔开的整数,表示N,K(1≤N≤100,0<K<50);
第二行共有N个用空格隔开的整数,为Ti。每个整数为1-50之间的数。
输出格式
一行,如果凑不齐K+3双,输出-1,否则输出长度差平方和的最小值。
输入样例
10 1
1 1 2 3 3 3 4 6 10 20
输出样例
5样例说明
第一双 1 1
第二双 2 3
第三双 3 3
第四双 4 6
题解
容易想到,我们设第$i$个人拥有筷子$c_{2i-1}$、$c_{2i}$,那么对于所有被选的筷子,一定有$c_{j} leqslant c_{j+1}$。
我们对筷子长度进行排序,然后直接dp即可。
#include <iostream> #include <algorithm> #include <cstring> #define MAX_N 100 #define MAX_M 50 using namespace std; int n, m; int a[MAX_N | 1]; int dp[MAX_N | 1][MAX_M + 4]; int main() { cin >> n >> m; m += 3; if(n < (m << 1)) return cout << -1, 0; for(register int i = 1; i <= n; ++i) { cin >> a[i]; } sort(a + 1, a + n + 1); for(register int k = 1; k <= m; ++k) { dp[(k << 1) - 1][k] = 2000000000; for(register int i = k << 1; i <= n; ++i) { dp[i][k] = dp[i - 1][k]; for(register int j = (k << 1) - 1; j < i; ++j) { dp[i][k] = min(dp[i][k], dp[j - 1][k - 1] + (a[i] - a[j]) * (a[i] - a[j])); } } } cout << dp[n][m]; return 0; }