GHOJ 666 筷子

题目描述

  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;
}
参考程序
原文地址:https://www.cnblogs.com/kcn999/p/10885469.html