UVa 10271 Chopsticks(经典DP)

题意:

有n个数据,给定k,要从中选出k+8个三元组(x,y,z,其中x<=y<=z),每选一次的代价为(x-y)^2,求最小代价和。

思路:

属于比较经典的一类动态规划了,首先是状态转移方程要思考清楚,然后就是题目本身的一些限制条件。

dp[i, j]表示前i个筷子选择j对(x, y, z)差值最小。

对于第i个筷子,就要考虑清楚了,第i个筷子参与第j对 与 第i个筷子不参与第j对。

dp[i][j] = min(dp[i-1][j], dp[i-2][j-1] + w);

初始化状态要搞清楚,dp[i, 0] = 0,因为要满足选择k+8组,所以其他的都要赋值INT_MAX;

师兄说,所有的数学问题都可以用数学归纳法解决,从小的方面入手或者说一步一步分析,步伐不要太大,

就可以一个很抽象的问题简单化。毕竟再复杂的问题都是可以由各个小问题叠加过来的。强大的数学思想,还有待于训练到编程中来。

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <climits>

#define min(a,b) (((a) < (b)) ? (a) : (b))

int dp[5010][1010];
int a[5010];

int main()
{
    int cases;
    scanf("%d", &cases);
    while (cases--)
    {
        int k, n;
        scanf("%d %d", &k, &n);
        k += 8;

        for (int i = n; i >= 1; --i)
            scanf("%d", &a[i]);

        for (int i = 1; i <= n; ++i)
        {
            dp[i][0] = 0;
            for (int j = 1; j <= k; ++j)
                dp[i][j] = INT_MAX;
        }
       
        for (int i = 3; i <= n; ++i) 
            for (int j = 1; j <= k; ++j)
                if (i >= j * 3 && dp[i-2][j-1] != INT_MAX)
                    dp[i][j] = min(dp[i-1][j], dp[i-2][j-1] + (a[i]-a[i-1]) * (a[i]-a[i-1]));

        printf("%d\n", dp[n][k]);
    }
    return 0;
}
posted @ 2012-11-19 20:42  kedebug  阅读(1308)  评论(1编辑  收藏  举报