Description
胡老师马上要搬新家了,可是搬家真的是一个很累的活,看着家里的n件物品, 胡老师已经凌乱了,因为物品实在太多。于是胡老师想了又想,决定先随便搬2* p件过去就行了。 现在,胡老师发现每搬一次的疲劳度是和左右手的物品的重量差的平方成正比,( 每次左手一件右手一件) ,如果胡老师左手拿重量为3的物品, 右手拿重量为6的物品, 则他搬完这次的疲劳度为(6-3)^2 = 9. 现在,胡老师很有忧伤,他不知道搬完这2p件物品以后的最低劳累度是多少,你作为他聪明的学生,来帮助他解决这个问题吧。
Input
有多组输入数据。 每组输入数据包含两行, 第一行是两个整数n和k(2<=2*p<=n<2000) 。n表示物品的总数,2*p表示现在要搬的物品数量(注意每次左右手各拿一个物品)。接下里第二行有n个正整数,分别每件物品的重量( 重量小于40000)。
Output
对于每组数据, 输出一行一个整数,表示他搬完这2p件物品以后最低的劳累度。
Sample Input
2 1 1 3
Sample Output
4 题意: 有n件物品,要你从里面选p(p*2<n)对物品出来,使得每一对差的平法的和最小。 解题思路: 考虑n个物品a>b>c>d>…..,最好的选法是ab一组,cd一组,ef一组…(可证)。先对n个物品排序,现在设dp[i][j]为从前j个物品里选i对出来,那么对于第j个物品,有两种选择,选或不选,即dp[i][j-1]或dp[i-1][j-2]+(a[j]-a[j-1])^2(由上面的推论知,尽量选择与之相邻的一个物品使其配对),dp[i][j]初始化为INF,表示无法到达,然后对于dp[0][j],不需要选任何物品,所以为0。 代码:
#include<cstdio>
#include<cstring>
#include<string>
#include<iostream>
#include<sstream>
#include<algorithm>
#include<utility>
#include<vector>
#include<set>
#include<map>
#include<queue>
#include<cmath>
#include<iterator>
#include<stack>
using namespace std;
const int INF=0x3f3f3f3f;
const double eps=1e-7;
const int mod=1000007;
const int maxn=2005;
int dp[maxn][maxn];
int a[maxn];
int main()
{
int n,k;
while(cin>>n>>k)
{
for(int i=1;i<=n;i++)
cin>>a[i];
sort(a+1,a+1+n);
memset(dp,INF,sizeof dp);
for(int i=0;i<=n;i++)
dp[0][i]=0;
for(int i=1;i<=k;i++)
{
for(int j=2;j<=n;j++)
dp[i][j]=min(dp[i][j-1],dp[i-1][j-2]+(a[j]-a[j-1])*(a[j]-a[j-1]));
}
cout<<dp[k][n]<<endl;
}
}