[题解]UVA10271 佳佳的筷子 Chopsticks

思路

这是一道 DP 好题,首先要搞清楚 \(dp\) 数组的含义,以及状态转移。

我们 \(dp_{i,j}\) 的含义是:取前 \(i\) 个数,形成 \(j\) 个三元组的最小权值和。

然后我们就可以来推状态转移方程了。

首先 \(dp\) 数组的初始值要设为无穷大,因为我们要求的是最小值所以我们需要设为无穷大

然后,我们要将 \(dp_{i,0}\) 赋为 \(0\),因为我们不选三元组,所以权值和自然就是 \(0\) 了。

最后我们的方程是有两种情况的,一种是选,一种是不选。

选的话就是用 \(dp_{i - 2,j - 1}\) 加上本次新增加的这个三元组的权值 \((a_{i - 1} - a_i) ^ 2\),即:\(dp_{i - 2,j - 1} + (a_{i - 1} - a_i)\)

不选就简单了,就是上一个状态嘛,即:\(dp_{i - 1,j}\)

这样我们的状态转移方程就出来了,即:\(dp_{i,j} = \min(dp_{i - 1,j},dp_{i - 2,j - 1} + (a_{i - 1} - a_i) ^ 2)\)

注:我们的 \(a\) 数组需要倒序输入,这样才好组成三元组。

Code

#include <bits/stdc++.h>  
  
using namespace std;  
  
const int N = 5010;  
int T,k,n;  
int arr[N];  
int dp[N][N];  
  
int main(){  
    ios::sync_with_stdio(0);  
    cin.tie(0);  
    cout.tie(0);  
    cin >> T;  
    while (T--){  
        cin >> k >> n;  
        k += 8;//要组成 k + 8 个三元组,所以需要加上 8   
        for (int i = n;i;i--) cin >> arr[i];//倒序输入   
        memset(dp,127,sizeof(dp));//赋为 INF   
        for (int i = 1;i <= n;i++) dp[i][0] = 0;  
        for (int i = 3;i <= n;i++){//枚举 i,j   
            for (int j = 1;j <= k;j++){  
                if (i >= 3 * j) dp[i][j] = min(dp[i - 2][j - 1] + (arr[i - 1] - arr[i]) * (arr[i - 1] - arr[i]),dp[i - 1][j]);  
                //这里 i >= 3 * j 的原因是:要组成 j 个三元组至少也得要 3 * j 个数   
            }  
        }  
        cout << dp[n][k] << endl;  
    }   
    return 0;  
}  
posted @ 2024-06-26 12:37  WBIKPS  阅读(26)  评论(0)    收藏  举报