1. 程式人生 > >hdoj-1421-搬寢室【DP】

hdoj-1421-搬寢室【DP】

循環 efi names sort pac ane recommend 7月 set

搬寢室

Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 21420 Accepted Submission(s): 7278


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

Author xhd
Source ACM暑期集訓隊練習賽(二)
Recommend lcy | We have carefully selected several similar problems for you: 1058 1978 1789 2159 2830
#include<stdio.h>
#include<string.h>
#include<algorithm> 
using namespace std;
const int maxn=2010;
int dp[maxn][maxn];
int a[maxn];
int min(int a,int b){
	return a<b?

a:b; } int main(){ int n,k; while(~scanf("%d%d",&n,&k)){ int i,j; for(i=1;i<=n;++i){ scanf("%d",&a[i]); } sort(a+1,a+n+1); memset(dp,0,sizeof(dp)); for(i=1;i<=k;++i){ dp[i*2][i]=dp[i*2-2][i-1]+(a[i*2]-a[i*2-1])*(a[i*2]-a[i*2-1]); for(j=i*2+1;j<=n;++j){ dp[j][i]=min(dp[j-1][i],dp[j-2][i-1]+(a[j]-a[j-1])*(a[j]-a[j-1])); } } printf("%d\n",dp[n][k]); } return 0; }


首先須要排序,由於相鄰的平方差一定是最好的選擇(之前一直不明確為甚麽要排序。只是如今懂了) dp【i】【j】:在前 i 件中選擇 j 對的的最優解;那麽:
當 i >2*j; dp【i】【j】= min(dp【i-1】【j】。dp【i-2】【j-1】+(a【i】-a【i-1】)*(a【i】-a【i-1】)) 當i==2*j dp【i】【j】=dp【i-2】【j-1】+(a【i】-a【i-1】)*(a【i】-a【i-1】)。
重要的一點是要把 j 對放在外層循環,之前放在內層了,竟然在杭電上也能過,只是明顯是錯誤的! 以下解釋一下: 對於取k對時:首先計算出 前k*2件,顯然這樣的情況在前 K*2 件要取得 k對,那麽必須全選;在考慮對於 i>2*K 時的情況,這樣就能夠逐步計算出對於 每一個 j 的不同的 i所相應的最優解
幾組特殊數據: 6 2 1 8 9 20 10 9 6 2 1 7 15 20 20 20 3 1 1 9 10

hdoj-1421-搬寢室【DP】