题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1421
方法:首先对于这些重量乱序的物品,需要排序来贪心初始化然每件物品在选择的时候,都是选择与其重量最接近的。然后建立状态转移方程,设F(k,i)为当选择第i物品的时候,从中选择k对物品的最小疲劳度,staff[i]为排序好了的物品中第i个的重量,方程如下:
{
(taff[2] - staff[1])^2, k==1 and i==2;
F(k,i) = Max( (staff[i]- staff[i-1])^2 , F(k,i-1) ), k==1 and i>=3;
Max( (staff[i]- staff[i-1])^2+F(k-1,i-2), F(k,i-1)), 1<k<=(i/2向下取整) and i>=3 ;
+INF, other condition;
}
问题最终解为:F(K,N)
基本思想就是 当探寻到第i个物品的时候,在选取k对的时候要做这样的考虑,首先当第i个物品的时候,无论i是奇数还是偶数,其都最少选出1对最多选出i/2向下取整对。这样就确定了k的范围。然后:
当k>1的时候1,第i个物品个之前前一个物品组合的疲劳度加上前面i-2个物品选择k-1对物品的疲劳度。2,不用第i个物品,直接从前面i-1个物品中选k对的疲劳度,如果前面i-1个物品选不出来k对,那么疲劳度为正无穷。最后比较这个两个疲劳度得到当前最优解。
当k==1,考虑1,第i个物品个之前前一个物品组合的疲劳度;2,2,不用第i个物品,直接从前面i-1个物品中选1对的疲劳度。最后比较得当前最优解。
感想:还是磕了很久的,要努力回忆并记住自己是怎么想出来的,这个比ac还重要。
代码:
#include<iostream> #include<math.h> #include<algorithm> //#include<queue> //#include<stack> using namespace std; int const MAX =0x3f3f3f3f; int MyMin(int x,int y) { return x<y ? x:y; } int dp[1001][2001]; int main() { int n,k; int staff[2001]; while(scanf("%d %d",&n,&k)!=EOF) { memset(dp,MAX,sizeof(dp)); for(int i=1;i<=n;i++) scanf("%d",&staff[i]); sort(staff+1,staff+1+n); dp[1][2] = (staff[2]- staff[1])*(staff[2]- staff[1]); for(int i = 3;i<=n;i++) { for(int x =1;x<=i/2;x++) { if(x==1) dp[x][i] = MyMin(dp[x][i-1],(staff[i]-staff[i-1])*(staff[i]-staff[i-1]) ); else dp[x][i] = MyMin(dp[x][i-1],dp[x-1][i-2]+(staff[i]-staff[i-1])*(staff[i]-staff[i-1]) ); } } cout<<dp[k][n]<<endl; } return 0; }