UVa 10271 - Chopsticks (dp)
题目链接:https://onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=14&page=show_problem&problem=1212
首先发现,最短的两只筷子一定是相邻的,如果不是,换成相邻的答案一定更优
考虑如果没有最长的筷子,那么设 \(dp[i][j]\) 表示前 \(i\) 只筷子组成了 \(j\) 套筷子,每只筷子有选或不选两种决策
而现在有最长的筷子这个限制,我们可以考虑将筷子长度从大到小排序,这样每套筷子中最长的一根,在当前决策时已经选择过了,因为长度大于等于最短的两根筷子,这样就不需要特殊考虑了
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 5010;
int T, n, k;
int a[maxn];
int dp[maxn][maxn];
bool cmp(int x, int y){
return x > y;
}
int sqr(int x){
return x * x;
}
ll read(){ ll s = 0, f = 1; char ch = getchar(); while(ch < '0' || ch > '9'){ if(ch == '-') f = -1; ch = getchar(); } while(ch >= '0' && ch <= '9'){ s = s * 10 + ch - '0'; ch = getchar(); } return s * f; }
int main(){
scanf("%d", &T);
while(T--){
scanf("%d%d", &k, &n);
for(int i = 1 ; i <= n ; ++i) scanf("%d", &a[i]);
sort(a + 1, a + 1 + n, cmp);
memset(dp, 0x3f, sizeof(dp));
dp[0][0] = 0;
for(int i = 1 ; i <= n ; ++i){
for(int j = 0 ; j <= min(i/3, k + 8) ; ++j){
dp[i][j] = min(dp[i][j], dp[i-1][j]);
if(i >= 2 && j >= 1) dp[i][j] = min(dp[i][j], dp[i-2][j-1] + sqr(a[i]-a[i-1]));
}
}
printf("%d\n", dp[n][k+8]);
}
return 0;
}