HDU-OJ-1421 搬寝室(巩固)

来源:互联网 发布:js decode 编辑:程序博客网 时间:2024/05/16 17:20

上次搜了题解,用那种非人类的方式解决了这道基础题。现在我们使用正常的DP思维方式和过程来更好地体会体会它。

题意:给出无序的n个数,每个物品重量Ai。给出搬物品的次数k,每次搬两个物品。(Ai1-Ai2)^2称之为badness,求出k次搬运之后,最小的badness之和。

思路:

首先确认类型。这是分组DP。因为每次取两个数,取k次就相当于分成k组。求出这 k组的最优性质。

其次是刻画状态。既然是分组DP,那么显然,dp[ i ][ j ],[ i ]表示前 i 组,[ j ]表示物品。

再次是无后效性。对于每一组,都不能产生后效,也就是说,推出当前组值的时候,之前组的值是唯一确定的。外层循环显然是组。接下来,内层循环要从 i*2 开始。为什么?因为 i*2 之前的 j 都被前面的组规划了(每组拿两个)。不能产生后效就不能改变前面的规划。

接下来是决策。什么样的决策能得到最优解?对于第 j 和第 j-1 件物品,我要么取,要么不取,做出dp值更小的决策。

考虑递推的起始条件:第0组的任意 j 物品badness都是0。(拿0次)

最后是状态转移方程。

dp[i][j] = min{dp[i][j-1], dp[i-2][j-1] + (A[j] - A[j-1])^2}
初始化的细节:要求最小值,初始化为无穷大。

代码如下:

/****************************************/ #include <cstdio> #include <cstdlib> #include <cstring> #include <algorithm> #include <cmath> #include <stack> #include <climits> #include <queue> #include <vector> #include <map> #include <string> #include <iostream> using namespace std;/****************************************/#define S (a[j-1] - a[j])*(a[j-1] - a[j])const int N = 2010, SUP = 2e9;int dp[N>>1][N], a[N];int main(){int n, k;while(~scanf("%d%d", &n, &k)) {for(int i = 1; i <= n; i++)scanf("%d", &a[i]);sort(a+1, a+n+1);for(int i = 1; i <= k; i++)for(int j = 0; j <= n; j++)dp[i][j] = SUP;for(int j = 0; j <= n; j++)dp[0][j] = 0;for(int i = 1; i <= k; i++)for(int j = i<<1; j <= n; j++)dp[i][j] = min(dp[i][j-1], dp[i-1][j-2] + S);printf("%d\n", dp[k][n]);}return 0;}


0 0