搬宿舍
Problem Description
搬寝室是很累的,xhd深有体会.时间追述2006年7月9号,那天xhd迫于无奈要从27号楼搬到3号楼,因为10号要封楼了.看着寝室里的n件物品,xhd开始发呆,因为n是一个小于2000的整数,实在是太多了,于是xhd决定随便搬2*k件过去就行了.但还是会很累,因为2*k也不小是一个不大于n的整数.幸运的是xhd根据多年的搬东西的经验发现每搬一次的疲劳度是和左右手的物品的重量差的平方成正比(这里补充一句,xhd每次搬两件东西,左手一件右手一件).例如xhd左手拿重量为3的物品,右手拿重量为6的物品,则他搬完这次的疲劳度为(6-3)^2 = 9.现在可怜的xhd希望知道搬完这2*k件物品后的最佳状态是怎样的(也就是最低的疲劳度),请告诉他吧.
Input
每组输入数据有两行,第一行有两个数n,k(2<=2*k<=n<2000).第二行有n个整数分别表示n件物品的重量(重量是一个小于2^15的正整数).
Output
对应每组输入数据,输出数据只有一个表示他的最少的疲劳度,每个一行.
Sample Input
2 1
1 3
Sample Output
4
刚开始的时候在DP专题中看到的这道题,然后想着用DP,然后想了想为什么不能用贪心啊,多简单啊,然后想着用DP做,还是没有好好分析问题,这道题中,当我选择了两件物品以后,对以后的选择是有影响的,因为当我遇到两个差值相同的物品时,选择不同的方案对这两个物品旁边的物品能不能在下一次选是有影响的,既然是有后效性的,我们就不能直接用贪心来做,这时候又回到了DP的思路,对于一个物品,我们将物品分成一对一对的,对于DP[i][j],我们定义为在前i个中选择j对物品的最小值,选择DP[i][j]我们有两种方法,一种是选择选择DP[i-1][j]的值和DP[i-2][j-1]+(node[i]-node[i-1])*(node[i]-node[i-1])的值选最小值,这道题让我重新理解了对于最优子结构的认识:每个阶段的最优状态可以从之前某个阶段的某个或某些状态直接得到,而无后效性是说不管之前这个状态是如何得到的。它和贪心的区别是:每个阶段的最优状态都是由上一个阶段的最优状态得到的(贪心)
#include<bits/stdc++.h>
using namespace std;
using LL=int64_t;
const int INF=0x3f3f3f3f;
int node[2005];
int dp[2005][2005];
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
int n,k;
while(cin>>n>>k) {
for(int i=1;i<=n;i++) cin>>node[i];
sort(node+1,node+1+n);
for(int i=0;i<=n;i++) {
dp[i][0]=0;
for(int j=1;j<=n;j++) {
dp[i][j]=INF;
}
}
for(int i=2;i<=n;i++){
for(int j=1;2*j<=i;j++){
if(j>k) break;
dp[i][j]=min(dp[i-2][j-1]+(node[i]-node[i-1])*(node[i]-node[i-1]),dp[i-1][j]);
}
}
cout<<dp[n][k]<<endl;
}
return 0;
}