SOJ 1685:chopsticks(dp)

 

题目链接

说实话挺喜欢soj的界面,简简单单,没有多余的东西hhh(但是简单到连内存限制,时间限制都看不到了。

题意是有个“奇葩”的主人公,吃饭要用三根筷子。两根短的一根长的。

现在给你n根筷子,要在里面挑k+8对筷子(一对三根,有一根最长的,设为Ai <= Bi <= Ci (Ai-Bi)^ 2 叫做 badness)使得 

$\sum ^{k}_{i=1}\left( A_{i}-B_{i}\right) ^{2}$ 最小

 emmmmm其实不放在dp分类里面我看不出是dp,以为是贪心(太菜了

dp[i][j]表示前i根筷子里面取j对的badness的最小值

正着取怎么取怎么不舒服,因为不知道以谁结尾,第i-3根在之前取过吗 第i-2根在之前取过吗 第i-1根在之前取过吗 有最大的跟这些匹配吗,

所以就由大到小取,只要 3 * j <= i,就有大的跟这一组对应。

转移方程dp[i][j] = min(dp[i-1][j], dp[i-2][j-1] + (l[i] - l[i-1])^2)

不过会卡内存,dp数组得设得刚刚好,不然就用滚动数组(菜到不会

时间复杂度O(kn)

 

代码如下

#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;

const int maxn = 5000 + 5;
int n, k, l[maxn], dp[maxn][maxn/5];

int main() {
    int T; scanf("%d", &T);
    while (T--) {
        scanf("%d%d", &k ,&n);
        k += 8;
        for (int i = 1; i <= n; i++) {
            dp[i][0] = 0;
            scanf("%d", &l[n-i+1]);
        }
        for (int i = 0; i <= n; i++) {
            dp[i][0] = 0;
            for (int j = 1; j <= k; j++)
                dp[i][j] = 0x3f3f3f3f;
        }
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= min(k, i / 3); j++) {
                dp[i][j] = min(dp[i-1][j], dp[i-2][j-1] + (l[i] - l[i-1]) * (l[i] - l[i-1]));
            }
        }
        printf("%d\n", dp[n][k]);
    }
    return 0;
}
View Code

 

posted @ 2019-02-19 15:48  Mrzdtz220  阅读(124)  评论(0编辑  收藏  举报