hdu1500过了,但还没全懂

这题看完感觉就是DP,然后我当然就用记忆化搜索打了,打着打着,觉得想法不一定对,但打完交了一遍,MLE,改小数组再交,就过了,但其实还没有完全理解透。算是混过的。

相当于DP的方法,dp[i][j]表示前i根筷子组成j组的最小值。我觉得关键的问题在于要先反着排序,然后如果筷子数刚好是人数的3倍时,最小的两根必定会在同一组中,且是一组中的较小的两根。

/*
 * hdu1500/win.cpp
 * Created on: 2012-7-27
 * Author    : ben
 */
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <ctime>
#include <iostream>
#include <algorithm>
#include <queue>
#include <set>
#include <map>
#include <stack>
#include <string>
#include <vector>
#include <deque>
#include <list>
#include <functional>
#include <numeric>
#include <cctype>
using namespace std;
const int MAXN = 5005;
const int MAXK = 1002;
const int MAX = 0x7fffffff;
int chops[MAXN];
int dp[MAXN][MAXK];

int dfs(int i, int j) {
    if(dp[i][j] >= 0) {
        return dp[i][j];
    }
    if(i == j * 3) {
        int ret1 = chops[i - 2] - chops[i - 1];
        ret1 *= ret1;
        ret1 += dfs(i - 2, j - 1);
        dp[i][j] = ret1;
    }else if(i > j * 3){
        int ret1 = dfs(i - 1, j);
        int ret2 = chops[i - 1] - chops[i - 2];
        ret2 *= ret2;
        ret2 += dfs(i - 2, j - 1);
        dp[i][j] = ret1 < ret2 ? ret1 : ret2;
    }else {
        dp[i][j] = MAX;
    }
    return dp[i][j];
}

int main() {
#ifndef ONLINE_JUDGE
    freopen("data.in", "r", stdin);
#endif
    int T, K, N;
    scanf("%d", &T);
    while(T--) {
        scanf("%d%d", &K, &N);
        for(int i = 0; i < N; i++) {
            scanf("%d", &chops[i]);
        }
        sort(chops, chops + N, greater<int>());
        memset(dp, -1, sizeof(dp));
        for(int i = 0; i < N; i++) {
            dp[i][0] = 0;
        }
        int ans = dfs(N, K + 8);
        printf("%d\n", ans);
    }
    return 0;
}
posted @ 2012-07-27 23:11  moonbay  阅读(181)  评论(0编辑  收藏  举报