【DP一维一边推】筷子
【题面】
共N根筷子,长度为 \(T1,T2,T3,...,TN\) 。组成 \(K+3\) 对,使每双的筷子长度差的平方和最小。
【输入格式】
输入文件共有两行,第一行为两个用空格隔开的整数,表示\(N,K(1≤N≤100,0<K<50\)),第二行共有N个用空格隔开的整数,为Ti每个整数为1~50之间的数。
【输出格式】
输出文件仅一行。如果凑不齐K+3双,输出-1,否则输出长度差平方和的最小值。
| 样例输入1 | 样例输出1 |
|------| ------|
| 10 1
1 1 2 3 3 3 4 6 10 20|5|
-
【算法分析】
-
dp
先\(sort\)这样第i和第i-1根就是差距最小的了. -
\(t[i][j]\)表示前i根组成j双筷子每双长度差的和的最小值。
-
在考虑第i根筷子时,需要做出的推测即使要不要把这只筷子加入到最优解中去,若加入,则其与第\((i-1)\)根筷子组成一对,\(t[i][j]=t[i-2][j-1]+(a[i]-a[i-1])*(a[i]-a[i-1])\),否则\(t[i][j]=t[i-1][j]\)
-
当然,上述推测过程依赖于以下思想:
当从小到大排好的 a,b,c,d 四根筷子组成两双时, ab,cd 这样的组合最优. 就是以上推测时采取的 将第i个筷子跟第i-1根组成一对 -
故dp方程这样写
\(t[i][j]=min(t[i][j],min(t[i-1][j],t[i-2][j-1]+(a[i]-a[i-1])*(a[i]-a[i-1])))\) -
【数据范围约定】
-
\(1≤N≤100,0<K<50\)
-
【AC代码】
#include<bits/stdc++.h>
#pragma GCC optimize(2)
#define temp (a[i]-a[i-1])
using namespace std;
int n,m,t[110][70],a[110];
bool cmp(int x,int y) {
return x<y;
}
int main() {
cin>>n>>m;
m=m+3;
if(n<2*m) {//如果凑不齐K+3双,输出-1
printf("-1");
return 0;
}
for(int i=1; i<=n; i++) {
for(int j=1; j<=n; j++) {
t[i][j]=63;//把t数组的每一位都赋值0x3f
}
}
for(int i=1; i<=n; i++) {
cin>>a[i];
}
sort(a+1,a+n+1,cmp);//使第i和第i-1根距离最小
t[0][0]=0;//
for(int i=1; i<=n; i++) {
for(int j=1; j<=min(i/2,m); j++) {
t[i][j]=min(t[i][j],min(t[i-1][j],t[i-2][j-1]+temp*temp));//dp方程,求筷子长度差最小的平方和
}
}
cout<<t[n][m];
//system("pause");
return 0;
}