搬寝室 (九度教程第 99 题)

搬寝室 (九度教程第 99 题)

时间限制:1 秒 内存限制:32 兆 特殊判题:否

1.题目描述:

搬寝室是很累的,xhd 深有体会.时间追述 2006 年 7 月 9 号,那天 xhd 迫于无奈要从 27 号楼搬到 3 号楼,因为 10 号要封楼了.看着寝室里的 n 件物品,xhd 开始发呆,因为 n 是一个小于 2000 的整数,实在是太多了,于是 xhd 决定随便搬 2k 件过去就行了.但还是会很累,因为 2k 也不小是一个不大于 n 的整数.幸运的是 xhd 根据多年的搬东西的经验发现每搬一次的疲劳度是和左右手的物品的重量差的平方成正比(这里补充一句,xhd 每次搬两件东西,左手一件右手一件).例如 xhd 左手拿重量为 3 的物品,右手拿重量为 6 的物品,则他搬完这次的疲劳度为(6-3)^2 = 9.
现在可怜的 xhd 希望知道搬完这 2k 件物品后的最佳状态是怎样的(也就是最低的疲劳度),请告诉他吧.
输入:
每组输入数据有两行,第一行有两个数 n,k(2<=2
k<=n<2000).第二行有 n 个整数分别表示 n 件物品的重量(重量是一个小于 2^15 的正整数).
输出:
对应每组输入数据,输出数据只有一个表示他的最少的疲劳度,每个一行.
样例输入:
2 1
1 3
样例输出:
4

2.基本思路

首先可以知道,对于重量为 a &lt; b &lt; c &lt; d a&lt;b&lt;c&lt;d a<b<c<d的四件物品, ( a , b ) (a,b) (a,b) ( c , d ) (c,d) (c,d)分别组合会获得的最小的疲劳度。因此对于所给的物品序列 O b j e c t [ n ] Object[n] Object[n]我们先对其进行升序排序,然后定义矩阵 d p [ k ] [ n ] dp[k][n] dp[k][n],矩阵元素 d p [ i ] [ j ] dp[i][j] dp[i][j]表示前j件物品中选取i对物品所获得的最小疲劳度。对于 d p [ i ] [ j ] dp[i][j] dp[i][j]主要由两种状态转移而来① o b j e c t [ j object[j object[j]和 o b j e c t [ j − 1 ] object[j-1] object[j1]成功组队② o b j e c t [ j ] object[j] object[j]无法和 o b j e c t [ j − 1 ] object[j-1] object[j1]组队,则可以得到如下递推方程:
d p [ i ] [ j ] = min ⁡ 0 ≤ i ≤ k , 2 i ≤ j ≤ n { d p [ i ] [ j − 1 ] , d p [ i − 1 ] [ j − 2 ] + ( o b j e c t [ j ] − o b j e c t [ j − 1 ] ) 2 } dp[i][j]=\min\limits_{0≤i≤k,2i≤j≤n}\{dp[i][j-1],dp[i-1][j-2]+(object[j]-object[j-1])^2 \} dp[i][j]=0ik,2ijnmin{dp[i][j1],dp[i1][j2]+(object[j]object[j1])2}
需要注意的是 2 i ≤ j ≤ n 2i≤j≤n 2ijn的限制条件,以及对于每一行开始时 j = = 2 i j==2i j==2i时dp[i][j]的初始化。

3.代码实现

#include <iostream>
#include <climits>
#include <algorithm>
#define N 2002
using namespace std;

int min(int a,int b){
    if(a<b)return a;
    else
        return b;
}

int object[N];
int dp[N/2][N];//dp[i][j]表示前j件物品中选择i对可以获得的最小疲劳值
int main()
{
    int n,k;
    while(~scanf("%d%d",&n,&k)){
        for(int i=1;i<=n;i++){
            scanf("%d",&object[i]);
        }
        for(int j=1;j<=n;j++){
            dp[0][j]=0;
        }
        sort(object+1,object+1+n);
        for(int i=1;i<=k;i++){
            for(int j=2*i;j<=n;j++){
                if(j==2*i){
                    dp[i][j]=dp[i-1][j-2]+(object[j]-object[j-1])*(object[j]-object[j-1]);//注意每一行行头的初始化操作
                }
                else
                    dp[i][j]=min(dp[i][j-1],dp[i-1][j-2]+(object[j]-object[j-1])*(object[j]-object[j-1]));
            }

        }
        printf("%d\n",dp[k][n]);
    }
    return 0;
}
/*
2 1
1 3
*/

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值