tyvj1125 JR‘s chop

描述

JR有很多双筷子。确切的说应该是很多根,因为筷子的长度不一,很难判断出哪两根是一双的。JR家里来了K个客人,JR留下他们吃晚饭。加上JR,JR的girl friend和JR的朋友内涵,共K+3个人。每人需要用一双筷子。JR只好清理了一下筷子,共N根,长度为T1,T2,T3,……,TN.现在他想用这些筷子组合成K+3双,使每双的筷子长度差的平方和最小。
输入格式

输入文件共有两行,第一行为两个用空格隔开的整数,表示N,K(1≤N≤100, 0<=K<50),第二行共有N个用空格隔开的整数,为Ti.每个整数为1~50之间的数。

输入

10 1
1 1 2 3 3 3 4 6 10 20

输出

5


今天终于领悟了dp的博大精深…….

这道题的状态并不难想到f[i][j]表示前i跟筷子拼成j双时的最小值;
但是在想方程的时候发现,

后效性消不掉

每次更新时都不能避免拆掉以前已经拼好的筷子;如果每一遍都扫着更新,那跟暴搜就没什么区别了;自然方程也是各种无语…想不到啊!!


后来发现是这样的:对于一个数,它的平方总是大于将它分为几部分后每部分的平方和;所以要想使平方和最小,可以将所有的高度sort一遍,每一根筷子都与其前一根或后面一根配对即可获得最优解(想不到反例,但不能严格证明,欢迎留言证明);所以对于每一次转移,我们可以选择第i根筷子选还是不选;
方程如下;

f[i][j]=min(f[i-1][j],f[i-2][j-1]+(high[i]-high[i-1])*(high[i]-high[i-1]));

初始化及细节在代码中说明

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
int f[1000][1000];
int a[1000];
int n,k;

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);

    cin>>n>>k;
    k+=3;//not k+=k+3 神错误!!注意点@自己
    for(int i=1;i<=n;i++)
        cin>>a[i];
    if(n<k*2){cout<<"-1";return 0;}//判断是否能够凑够;

    sort(a+1,a+n+1);

    memset(f,1,sizeof f);//初始化为最大值
    for(int i=0;i<=n;i++) f[i][0]=0;//凑够0双代价为0,注意从0开始,否则1将无法转移  

    int i,j;
    for(i=1;i<=n;i++)
        for(j=1;(j<=k)&&(j<=i/2);j++)
                f[i][j]=min(f[i-1][j],f[i-2][j-1]+(a[i]-a[i-1])*(a[i]-a[i-1]));

    cout<<f[n][k];
    return 0;
}
  • 0
    点赞
  • 0
    评论
  • 0
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

©️2021 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值