[题解]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;
}

浙公网安备 33010602011771号