1. 程式人生 > >迎春舞會之三人組舞——dp

迎春舞會之三人組舞——dp

文章目錄

題目

題目連結

初看此題,難免想起這道題目

但仔細想想,發現中間那個人的標記會很難搞

於是便有了如下思路

思路

dp[i][j]表示在前i個人中分成j組的最小殘疾程度

便有如下狀態轉移方程

dp[i][j] = min(dp[i-1][j],dp[i-2][j-1]+(num[i]-num[i-1])^2)

但有以下要點

i - 1 >= j * 3

 dp[i-1][j]

才合法

但中間那個怎麼確定前 i 箇中一定存在一個沒用過且比方程中的

num[i]&&num[i-1]

高呢?

就有如下技巧

讀入時

for(i = 1;i <= n;i++)
        Read(num[n - i + 1]);

題目說了保證升序

這樣讀入保證了降序

迴圈時

for(i = 3;i <= n;i++)
    {
        for(j = 1;j <= i / 3;j++)
        {
        //j * 3 <= i的,那麼在前i個當中一定存在一個比num[i],num[i - 1]大的
        //因為num[i],num[i - 1]是前i箇中最小的
dp[i][j] = dp[i - 2][j - 1] + M(num[i] - num[i - 1]); dp[i][j] = Min(dp[i][j],i - 1 >= j * 3?dp[i - 1][j]:0x7f7f7f); } }

code

#include <cstdio>
#include <cstring>
#include <algorithm>
#define M(x) (x) * (x)
using namespace std;
const int MAXN =
5001; template<typename T> inline void Read(T &x) { char a = getchar(); bool f = 0; x = 0; while(a > '9'||a < '0') {if(a == '-') f = 1;a = getchar();} while(a >= '0'&&a <= '9') {x = x * 10 + a - '0';a = getchar();} if(f) x *= -1; } template<typename T> inline T Min(T a,T b) {if(a < b) return a;return b;} int num[MAXN]; int dp[MAXN][1001]; int main() { int n,m,i,j; Read(m),Read(n); for(i = 1;i <= n;i++) Read(num[n - i + 1]); for(i = 3;i <= n;i++) { for(j = 1;j <= i / 3;j++) { dp[i][j] = dp[i - 2][j - 1] + M(num[i] - num[i - 1]); dp[i][j] = Min(dp[i][j],i - 1 >= j * 3?dp[i - 1][j]:0x7f7f7f); } } printf("%d",dp[n][m]); }