搬东西 dp

搬东西

现有n个扁担以及一辆货车,扁担一次挑两个货物,货车可以装K个货物,货车只能运送一次货物。

现在qwb要把总共2n+k个货物搬到某个地方。现在qwb想选K个货物让货车先运走,然后剩下的2n个货物由他自己用扁担云过去,但是两个货物重量不均匀的话,会使得qwb感到很难受,每次会造成image.png的疲劳值,wi和wj是每次选的两个货物的重量,qwb想要n次运送后,使得image.png疲劳值的和最小。

第一行两个整数 n和k (2 ≤ n ≤ 100,000),(1≤ k≤ 20).

第二行2n+k个, w1, w2, ..., w2n+k, wi是每个货物的重量 (1 ≤ wi ≤ 1,000,000,000).

输出一行,疲劳值的最小值。

input

3 2 

1 3 4 6 3 4 100 200

output

5

这个题目是一个dp,开始没有意识到,通过这个题,我感觉我太依赖别人了,这样不太好。

dp[i][j] 表示前面 i 个物品,选出来 j 个 的最小疲劳值。

如果已经选出来 2*n 个物品,怎么算疲劳值最小,就应该是 排序,相邻的放在一起就是疲劳值最小的。

如果 i-j 是奇数,就是说那就是-  如果是偶数就是+

所以可以得到转移方程 dp[i][j]=min(dp[i-1][j]+(j-i)%2==1?-a[i]:+a[i],dp[i-1][j-1])

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <iostream>
#include <queue>
#include <string>
#include <vector>
#include <map>
#define inf 0x3f3f3f3f
#define inf64 0x3f3f3f3f3f3f3f3f
using namespace std;
const int maxn = 3e5 + 10;
typedef long long ll;
ll dp[maxn][30];
ll w[maxn];

int main()
{
    int n, k;
    scanf("%d%d", &n, &k);
    for (int i = 1; i <= 2*n+k; i++) scanf("%lld", &w[i]);
    sort(w + 1, w + 1 + 2*n+k);
    for(int i=1;i<=2*n+k;i++)
    {
        for(int j=0;j<=k;j++)
        {
            if (j == 0) dp[i][j] = dp[i - 1][j] + (i % 2 == 1 ? -w[i] : w[i]);
            else dp[i][j] = min(dp[i - 1][j] + ((i - j) % 2 == 1 ? -w[i] : w[i]), dp[i - 1][j - 1]);
        }
    }
    printf("%lld\n", dp[2*n+k][k]);
    return 0;
}
View Code

猜你喜欢

转载自www.cnblogs.com/EchoZQN/p/11252749.html
DP
DP?
今日推荐