3031:筷子(stick)  动态规划

题目描述

中国人吃饭必须要用筷子。C先生与常人不同,他的一副筷子有3只,一对再加上一根比较长的,用来穿比较大的食物。两只较短的筷子的长度应该尽可能接近,但是最长的那根的长度是无所谓的。如果一副筷子的长度分别是A,B,C(A<=B<=C),则用(A-B)2的值表示这副筷子的质量,显然这个值越小,质量越高。

       C先生邀请了K个朋友去吃饭,而且他要为每个人准备一副这种特殊的筷子。C先生的家里有8个人,因此你总共必须准备K+8副筷子。不过C先生发现他的筷子有各种各样不同的长度,他必须找到一种办法搭配好K+8副筷子,使得这些筷子的质量值之和最小。

输入格式

第一行有一个整数T,表示文件中共有T组测试数据。T的值不超过20。每一组测试数据的第一行是两个整数K和N,(0<=K<=1000, 3K+24<=N<=5000)。K是邀请朋友的人数,N是C先生家里储备的筷子总根数。接下来的一行有N个正整数,表示这N根筷子的长度;这N个数是从小到大给出的,并且每一根筷子的长度值不超过32000。

输出

对于每一组输入数据,输出单独一行,表示最小的质量值之和。你的答案应当写到stick.out中。

样例输入

1
1 40
1 8 10 16 19 22 27 33 36 40 47 52 56 61 63 71 72 75 81 81 84 88 96 98 103 110 113 118 124 128 129 134 134 139 148 157 157 160 162 164

样例输出

23

结题思路:

动态规划问题,难点在于要选3只筷子,因为C筷子比A,B筷子都要大,由题意知筷子从小到大排列,所以应该想到倒着每三只筷子更新,f[i][j]表示从最后一只筷子到第i只筷子(包括)组成j组筷子的最优解,条件是((n-i)>=j*3)这样才能够用。动态转移方程为:
f[i][j]=min(f[i+2][j-1]+(a[i+1]-a[i])*(a[i+1]-a[i]),f[i+1][j]);当选i时,i+1,i+2也要选, i+2只筷子一定比i,i+1只筷子大,所以得出上式前半部分,当第i不选时,f[i][j]值与f[i+1][j]一样,得出后半部分,再注意初始化即可。
参考程序:

//
//  main.cpp
//  ylzx3031
//
//  Created by 胡竣峰 on 14-8-23.
//  Copyright (c) 2014年 胡竣峰. All rights reserved.
//

#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=5005;
int a[N],f[N][N/5];
int main()
{
    int t;
    cin>>t;
    while (t--){
        memset(a,0,sizeof(a));
        memset(f,0x7f,sizeof(f));
        int n,k;
        cin>>k>>n;
        k+=8;
        for (int i=1;i<=n;i++) cin>>a[i];
        for (int i=1;i<=n;i++) f[i][0]=0;
        for (int i=n;i>=1;i--)
            for (int j=1;j<=k;j++)
                if (n-i>=3*j)
                    f[i][j]=min(f[i+2][j-1]+(a[i+1]-a[i])*(a[i+1]-a[i]),f[i+1][j]);
        cout<<f[1][k]<<endl;
    }
}
    原文作者:动态规划
    原文地址: https://blog.csdn.net/qq278053122/article/details/38782797
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞