【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;
}
posted @ 2019-07-26 07:33  半笙、凡尘  阅读(300)  评论(1)    收藏  举报