HDU 1421 搬寝室 (DP)

搬寝室
Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u
Submit  Status  Practice  HDU 1421

Description

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

Input

每组输入数据有两行,第一行有两个数n,k(2<=2*k<=n<2000).第二行有n个整数分别表示n件物品的重量(重量是一个小于2^15的正整数).
 

Output

对应每组输入数据,输出数据只有一个表示他的最少的疲劳度,每个一行.
 

Sample Input

2 1 1 3
 

Sample Output

4
 

 

之前做的都是自底向上填表的DP,这是专题里第一题自顶向下带备忘的DP,有点不习惯,想了一两个小时还是没思路,参考了网上题解,虽然自己写出了AC代码但还没有彻底理解,待加强。

思路:首先,对于排序后的数组,于一个数构成最小方差的数一定是与它相邻的,不是前一个就是后一个,所以应该一对一对取相邻的。

     其次,对于排序后的数组,要从这n个数里去k对,先分析第n个数,这个数要么取要么不取,如果要取,就必须和n-1个构成一对,因为在上面说了,与它成对的不是它前面那个就是它后面那个,因为已经是第n个,它后面的数不存在,所以只能取第n-1个来构成一对。所以可以依照此思路来递归。

   开一个二维数组,照惯例取名为DP,DP[n][k]表示从n个数里取k对,再用一个一维数组存输入的值(要排序)。

   当n==2*k时,DP[n][k] = DP[n - 2][k - 1] + (S[n] - S[n - 1])^2            因为所有数都要取,没必要比较什么。

   当n > 2*k时,DP[n][k] = min(DP[n - 2][k - 1] + (S[n] - S[n - 1])^2,DP[n - 1][k])     即要么取第n和n-1个构成一对,要么舍弃第n个重新再算.

 

 1 #include<stdio.h>
 2 #include<stdlib.h>
 3 #include<string.h>
 4 #define    MAX    2005
 5 #define    INF    2147483640
 6 
 7 int    DP[MAX][MAX / 2];
 8 int    S[MAX];
 9 
10 int    fx(int n,int k);
11 int    my_min(int i ,int j);
12 int    comp(const void * a,const void * b);
13 int    main(void)
14 {
15     int    n,k;
16 
17     while(scanf("%d%d",&n,&k) != EOF)
18     {
19         memset(DP,-1,sizeof(DP));
20 
21         for(int i = 1;i <= n;i ++)        //下标从1开始
22             scanf("%d",&S[i]);
23 
24         qsort(&S[1],n,sizeof(S[0]),comp);
25         fx(n,k);
26         printf("%d\n",DP[n][k]);
27     }
28 
29     return    0;
30 }
31 
32 int    fx(int n,int k)
33 {
34     if(DP[n][k] != -1)
35         return    DP[n][k];
36 
37     if(k == 0 || n == 0)
38         DP[n][k] = 0;
39     else    if(n < 2 * k)
40         DP[n][k] = INF;
41     else    if(n == 2 * k)
42         DP[n][k] = fx(n - 2,k - 1) + (S[n] - S[n - 1]) * (S[n] - S[n - 1]);
43     else    
44         DP[n][k] = my_min(fx(n - 1,k),fx(n - 2,k - 1) + (S[n] - S[n - 1]) * (S[n] - S[n - 1]));
45     
46     return    DP[n][k];
47 }
48 
49 int    my_min(int i ,int j)
50 {
51     return    i < j ? i : j;
52 }
53 
54 int    comp(const void * a,const void * b)
55 {
56     return    *(int *)a - *(int *)b;
57 }
View Code

 

转载于:https://www.cnblogs.com/xz816111/p/4170316.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值