hdoj1421:搬寢室(dp基礎題)
目錄
搬寢室
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
解題思路:
對n個物品的重量sort
dp[i][j]表示前i個裡面選j對,分兩種情況
1)選a[i],則肯定會選a[i-1],在前i-2個裡面選j-1對,則dp[i][j]=dp[i-2][j-1]+(a[i]-a[i-1])*(a[i]-a[i-1])
2)不選a[i]那麼就要在前i-1個之前選j對,則dp[i][j]=dp[i-1][j]
狀態轉移方程:
dp[i][j]=min(dp[i-1][j],dp[i-2][j-1]+(a[i]-a[i-1])*(a[i]-a[i-1]))
dp[i][j]初始為比較大的數
ac程式碼:
注意要把dp[maxn][maxn]陣列放在main()外面,而且應該是dp[maxn][maxn/2],分配太多的記憶體空間會使程式錯誤
#include <iostream> #include <cmath> #include <algorithm> #include <queue> #include <cstring> #define ll long long int #define maxn 2005 using namespace std; ll dp[maxn][1005],a[maxn]; int main() { int n,k,i,j; while(scanf("%d %d",&n,&k)!=EOF) { for(i=1;i<=n;i++)//後面有i-1,所以陣列下標從1開始 scanf("%lld", &a[i]); sort(a+1,a+1+n); for(i=1;i<n;i++) for(j=1;j<=n/2;j++) dp[i][j]=INT_MAX; for(j=1;j<=k;j++) { for(i=j*2;i<=n;i++) { dp[i][j]=min(dp[i-1][j],dp[i-2][j-1]+(a[i-1]-a[i])*(a[i-1]-a[i])); } } printf("%lld\n",dp[n][k]); } return 0; }