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;

}

你可能感兴趣的:(HDU)