二维DP hdu 1421 搬寝室问题

题目链接 ---------->http://acm.hdu.edu.cn/showproblem.php?pid=1421<-------------

题目分析:

  有n样东西,需要搬k次,每次搬两个,搬2*k个 ,求最少力气。很明显绝对值差值越小越好,于是读入n个物品质量后排序,每一个物品只有可能与前一个物品或后一个物品一起搬,绝对值才是可能当前最小。于是有DP思路,二维DP 数组 dp[i][j] 表示,到达选择第i个物品时,已经选了j对成功的物品的最小力气。当到达第i个物品时,可以选择是否选择搬动该物品 。所以有转移方程 dp[i][j] = min(dp[i - 2][j - 1] + (a[i - 1] - a[i - 2])^2,dp[i - 1][j]); 当然选择第i个物品时,可以规定j的范围,2*j <= i 已经选过的总物品数至少为选中对数两倍。由于这里取小值,全初始为0并不好,应当初始为一个极大值INF = 0x3f3f3f3f; 举个例子 当选过第六个物品,前面成功选了3对时:  dp[6][3] = min(dp[4][2] + (a[5] - a[4])^2 , dp[5][3]); 然而我们明白dp[5][3] 在前面并不会循环到,因为有限制条件 2*j <= i; 如果全初始化为0,那么这个选取最小值就会出错(为0)所以我们将其dp全初始化为最大值。然后只有 dp[i][0] = 0 (到达任何一个物品,前面选了0对,最小值为0)。最后 输出选到n个物品,选了k对的值就可以。也就是dp[n][k];

代码君:

 1 #include <iostream>
 2 #include <algorithm>
 3 #include <cstdio>
 4 #include <string.h>
 5 
 6 using namespace std;
 7 #define MAX 2010
 8 #define M (a[i - 1] - a[i - 2])
 9 #define INF 0x3f3f3f3f
10 
11 int dp[MAX][MAX];
12 int a[MAX];
13 int min(int a , int b) {return a < b ? a : b ;}
14 int n , k;
15 void init()
16 {
17     memset(dp,INF,sizeof(dp));
18     for(int i = 0 ; i <= n; i++) dp[i][0] = 0;
19     return ;
20 }
21 
22 
23 int main()
24 {
25     while(cin >> n >> k)
26     {
27         init();
28 
29         for(int i = 0; i < n ; i++) cin >> a[i];
30         sort(a , a + n);
31         init();
32 
33         for(int i = 1 ; i <= n ; i++)
34         {
35             for(int j = 1 ; 2 * j <= i && j <= k ; j++)
36             {
37                 dp[i][j] = min(dp[i - 2][j - 1] + M * M , dp[i - 1][j]);
38             }
39         }
40 
41         cout << dp[n][k] << endl;
42     }
43     return 0;
44 }
原文地址:https://www.cnblogs.com/ticsmtc/p/5241245.html