HDU1421:搬寢室(DP)

搬寢室
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 33811 Accepted Submission(s): 11570

Problem Description
搬寢室是很累的,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希望知道搬完這2*k件物品後的最佳狀態是怎樣的(也就是最低的疲勞度),請告訴他吧.

Input
每組輸入數據有兩行,第一行有兩個數n,k(2<=2*k<=n<2000).第二行有n個整數分別表示n件物品的重量(重量是一個小於2^15的正整數).

Output
對應每組輸入數據,輸出數據只有一個表示他的最少的疲勞度,每個一行.

Sample Input
2 1
1 3

Sample Output
4

Author
xhd

我一開始的做法是單獨把第一列先給填上去,因爲除了第一列,後面的幾列填的時候都要和前面的一列有聯繫。

  • 第一列:
    1.列首元素 :因爲上面沒有元素可以跟他比較大小,所以直接把(a[i] - a[i-1]) * (a[i] - a[i-1]);填入。
    2.非列首元素:因爲要和上面的元素比較取最小值,所以 = std::min(dp[i-1][1],(a[i] - a[i-1]) * (a[i] - a[i-1])};

  • 非第一列:
    1.列首元素:因爲上面沒有元素可以跟他比較大小,所以dp[i][j] = (a[i] - a[i-1]) * (a[i] - a[i-1]) + dp[i-2][j-1];
    2.非列首元素,因爲要和上面的元素比較取最小值,所以dp[i][j] = std::min(dp[i-1][j](這是不選的情況),(a[i] - a[i-1]) * (a[i] - a[i-1]) + dp[i-2][j-1]);

下面是我自己舉得一個例子:
6 2
1 3 6 7 9 10(順序任意)
在這裏插入圖片描述
附上ac代碼:

#include <stdio.h>
#include <iostream>
#include <algorithm>
#include <string.h>
#include <ctype.h>
#include <queue>
#include <cmath>
#define INF 0x3f3f3f3f
#define mod 1000000007
using namespace std;
typedef long long int ll;
ll a[3000];
ll dp[2010][1005];  //wa就開ll
int main() {
    int n,k;
    while(cin >> n >> k) { //每組輸入數據
        a[0] = -INF; //讓負INF永遠填在a[0]的那個位置上
        for(int i = 1; i <= n; i++) {
            cin >> a[i];
        }
        sort(a,a+n+1);
        memset(dp,0,sizeof(dp));
        for(int i = 2; i <= n; i++) {
            if(i == 2) {
                dp[2][1] = (a[2] - a[1]) * (a[2] - a[1]); //首元素
            } else {
                dp[i][1] = std::min(dp[i-1][1],(a[i] - a[i-1]) * (a[i] - a[i-1]));
            }
        }
        for(int j = 2; j <= k; j++) {
            dp[2*j][j] = dp[2*j-2][j-1] + (a[2*j] - a[2*j-1]) * (a[2*j] - a[2*j-1]); //首元素
            for(int i = 2*j + 1; i <= n; i++) {
                dp[i][j] = std::min(dp[i-1][j],dp[i-2][j-1] + (a[i] - a[i-1]) * (a[i] - a[i-1]));
            }
        }
//    for(int i = 0; i <= n; i++) {             自檢用
//        for(int j = 0; j <= k; j++) {
//            cout << dp[i][j] << " ";
//        }
//        cout << endl;
//    }
        cout << dp[n][k] << endl;
    }
    return 0;
}

 


然後寫完發現,反正dp數組的第0列全是0,加了沒影響,乾脆並在一起了,就比較簡潔。
ac代碼如下:

#include <stdio.h>
#include <iostream>
#include <algorithm>
#include <string.h>
#include <ctype.h>
#include <queue>
#include <cmath>
#define INF 0x3f3f3f3f
#define mod 1000000007
using namespace std;
typedef long long int ll;
ll a[3000];
ll dp[2010][1005];  //wa就開ll
int main() {
    int n,k;
    while(cin >> n >> k) { //每組輸入數據
        a[0] = -INF; //讓負INF永遠填在a[0]的那個位置上
        for(int i = 1; i <= n; i++) {
            cin >> a[i];
        }
        sort(a,a+n+1);
        memset(dp,0,sizeof(dp)); //把所有空格都填0
        for(int j = 1; j <= k; j++) {
            dp[2*j][j] = (a[2*j] - a[2*j-1]) * (a[2*j] - a[2*j-1]) + dp[2*j-2][j-1];
            for(int i = 2 * j + 1; i <= n; i++) {
                dp[i][j] = std::min(dp[i-1][j],dp[i-2][j-1] + (a[i] - a[i-1]) * (a[i] - a[i-1]));
            }
        }
//    for(int i = 0; i <= n; i++) {             自檢用
//        for(int j = 0; j <= k; j++) {
//            cout << dp[i][j] << " ";
//        }
//        cout << endl;
//    }
        cout << dp[n][k] << endl;
    }
    return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章