HDU 1421 搬寝室 动态规划

Description

胡老师马上要搬新家了,可是搬家真的是一个很累的活,看着家里的n件物品, 胡老师已经凌乱了,因为物品实在太多。于是胡老师想了又想,决定先随便搬2* p件过去就行了。
现在,胡老师发现每搬一次的疲劳度是和左右手的物品的重量差的平方成正比,( 每次左手一件右手一件) ,如果胡老师左手拿重量为3的物品, 右手拿重量为6的物品, 则他搬完这次的疲劳度为(6-3)^2 = 9.
现在,胡老师很有忧伤,他不知道搬完这2p件物品以后的最低劳累度是多少,你作为他聪明的学生,来帮助他解决这个问题吧。

Input

有多组输入数据。
每组输入数据包含两行, 第一行是两个整数n和k(2<=2*p<=n<2000) 。n表示物品的总数,2*p表示现在要搬的物品数量(注意每次左右手各拿一个物品)。接下里第二行有n个正整数,分别每件物品的重量( 重量小于40000)。

Output

对于每组数据, 输出一行一个整数,表示他搬完这2p件物品以后最低的劳累度。

Sample Input

 
  
2 1
1 3 

Sample Output

4
题意:
有n件物品,要你从里面选p(p*2<n)对物品出来,使得每一对差的平法的和最小。
解题思路:
考虑n个物品a>b>c>d>.....,最好的选法是ab一组,cd一组,ef一组...(可证)。先对n个物品排序,现在设dp[i][j]为从前j个物品里选i对出来,那么对于第j个物品,有两种选择,选或不选,即dp[i][j-1]或dp[i-1][j-2]+(a[j]-a[j-1])^2(由上面的推论知,尽量选择与之相邻的一个物品使其配对),dp[i][j]初始化为INF,表示无法到达,然后对于dp[0][j],不需要选任何物品,所以为0。
代码:
#include<cstdio>
#include<cstring>
#include<string>
#include<iostream>
#include<sstream>
#include<algorithm>
#include<utility>
#include<vector>
#include<set>
#include<map>
#include<queue>
#include<cmath>
#include<iterator>
#include<stack>
using namespace std;
const int INF=0x3f3f3f3f;
const double eps=1e-7;
const int mod=1000007;
const int maxn=2005;
int dp[maxn][maxn];
int a[maxn];
int main()
{
        int n,k;
      while(cin>>n>>k)
      {
              for(int i=1;i<=n;i++)
                cin>>a[i];
              sort(a+1,a+1+n);
              memset(dp,INF,sizeof dp);
              for(int i=0;i<=n;i++)
                dp[0][i]=0;
              for(int i=1;i<=k;i++)
              {
                for(int j=2;j<=n;j++)
                dp[i][j]=min(dp[i][j-1],dp[i-1][j-2]+(a[j]-a[j-1])*(a[j]-a[j-1]));
              }
              cout<<dp[k][n]<<endl;

      }
}


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值