题意:从n个物品里挑出2k个物品,每次拿两个,花费是两物品重量的平方差,求最小的花费
数据范围:2 <= 2*k <= n < 2000,重量不超过2^15
思路:考虑有确定的2k个物品,确定一种顺序使花费最小
可以证明,按重量对这2k个物品排序,然后相邻物品两两配对花费是最小的
设总花费是(a-b) ^ 2 + (c-d) ^ 2 + .... etc,去括号得到a^2+b^2+...一串平方和为定值
又当a<b<c<d时,ab+cd < ad+bc,就证明了这个结论
考虑dp[i][j]表示前i个物品,取走了j对物品时的最小花费,对于每个i,决策有取这一对和不取这一对,转移为:dp[i][j] = min(dp[i-1][j], dp[i-2][j-1]+cost(i, i-1))
答案为dp[n][k]
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #define INF 0x3f3f3f3f 5 using namespace std; 6 7 const int mx = 1010; 8 int a[mx*2], dp[2*mx][mx]; 9 10 int solve(int i, int j){ 11 int k = a[i]-a[j]; 12 return k*k; 13 } 14 15 int main(){ 16 int n, k; 17 while (scanf("%d%d", &n, &k) == 2){ 18 memset(dp, INF, sizeof(dp)); 19 for (int i = 1; i <= n; i++){ 20 scanf("%d", &a[i]); 21 dp[i][0] = 0; 22 } 23 dp[0][0] = 0; 24 sort(a+1, a+n+1); 25 for (int i = 2; i <= n; i++) 26 for (int j = 1; j <= k; j++) 27 dp[i][j] = min(dp[i-1][j], dp[i-2][j-1]+solve(i, i-1)); 28 printf("%d ", dp[n][k]); 29 } 30 return 0; 31 }