题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1421
解题思路:这是一道典型的dp问题。状态转移思想:将物品按质量递增排序后,从前i件物品中拿走j对(j*2<=i)时,
(1)不拿第i件,则dp[i][j]=dp[i-1][j],这个毫无疑问。
(2)拿第i件物品,则第i件物品肯定和第i-1件物品一起拿,则dp[i][j]=dp[i-2][j-1]+(a[i]-a[i-1])^2,即从前i-2件中拿j-1对的疲劳值加上拿了最后两件物品的疲劳值(当然,由前到后处理的,i和j前面的所有情况都已经处理好了,都是最小值)。状态转移方程:dp[i][j]=min(dp[i-1][j],dp[i-2][j-1]+(a[i-1]-a[i-2])*(a[i-1]-a[i-2]))。
注:此处用a[i-1]-a[i-2]是因为a是从下标0开始的。
AC代码:
1 #include<bits/stdc++.h> 2 using namespace std; 3 int a[2005],dp[2005][1005]; 4 const int INF=0x3f3f3f3f; 5 int main() 6 { 7 int n,k; 8 while(cin>>n>>k){ 9 memset(dp,INF,sizeof(dp));//初始化为最大值,以便比较取最小值 10 for(int i=0;i<n;i++){ 11 cin>>a[i]; 12 dp[i][0]=0;//同时将前i件物品中取走j=0对赋初值为0,不需要选任何物品 13 } 14 sort(a,a+n);//排序 15 for(int i=2;i<=n;i++){//i从2开始,枚举到(包括)n,题目有要求 16 for(int j=1;j*2<=i&&j<=k;j++)//j是枚举到k 17 dp[i][j]=min(dp[i-1][j],dp[i-2][j-1]+(a[i-1]-a[i-2])*(a[i-1]-a[i-2]));//从0开始 18 } 19 cout<<dp[n][k]<<endl; 20 } 21 return 0; 22 }