uva10271 经典DP

来源:互联网 发布:阿里旺旺软件下载 编辑:程序博客网 时间:2024/06/05 15:45

题目大意:
给出k和n k + 8代表的是人的个数 n是筷子的个数 给出筷子的长度
每个人需要三根筷子 A,B,C 前两根为较短的 后一根是最长的
求怎样选择才能使得(A-B)*(A-B)的值的总和最小

思路:
DP,
状态转移方程:dp[i][j] = min(dp[i - 1][j ],dp[i - 2][j - 1] + (a[i] - a[i - 1])*(a[i] - a[i - 1]))
其中a[i]是筷子的长度从大到小。
dp[i][j]表示的是到了第i根筷子和第j对筷子的总和最小值。
dp[i - 1][j] 表示第i根筷子不参与到第j对筷子中。
dp[i - 2][j - 1] 表示的是第i根筷子参与到第j对筷子中,并且与第i-1根配对了。

代码:

#include <iostream>using namespace std;#include <cstring>#include <stdio.h>const int maxn = 0x3ffffff;int dp[5010][5010];int a[5010];int main() {    int kases;    scanf("%d",&kases);    while(kases--) {        int k,n;        scanf("%d %d",&k,&n);        k = 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] = maxn;        }        for(int i = 3; i <= n; i++) {            for(int j = 1; j <= k; j++) {                if(i >= 3 * j && dp[i - 2][j - 1] != maxn)                    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;}
0 0