HDU-1421 搬寝室(递推,DP,数学)2017寒假集训

题意:从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\n", dp[n][k]);
29     }
30     return 0;
31 }

猜你喜欢

转载自www.cnblogs.com/QAQorz/p/9017021.html