J. Bottles 二维费用背包问题

http://codeforces.com/contest/730/problem/J

3

4    36    1

90   45   40

 

其实可以知道,选出多少个瓶子呢?是确定的,当然选一些大的。

那么问题转化为:

在n个瓶子中,选出k个,然后把剩余的n - k个瓶子得液体转移过去这k个里面,费用最小。其实就是使得剩余的n - k个瓶子的拥有液体数最小,那么其实就是需要那k个瓶子得拥有液体数最多。

dp[i][k][j]表示在前i个物品中,选出了k个物品,产生的总容量是j的时候,拥有液体数的最大值。

因为选出了k个东西,我们肯定是拥有一个容量的了,那么如果这n件物品,选出任意的k件东西,如果能产生相同的容量,我当然是选一些已经用了最多的,这样n-k个物品,转移液体过来,费时减小。

最后,还需要输出最小代价,就是,比如上面的样例,选容量是90是可以得,选容量是45也可以,那么就看看那个的代价更小了。

不一定容量大的,代价就小,因为可能用的不满。容量小的,就算用得满,也很小。

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <assert.h>
#define IOS ios::sync_with_stdio(false)
using namespace std;
#define inf (0x3f3f3f3f)
typedef long long int LL;


#include <iostream>
#include <sstream>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <string>
const int maxn = 1e2 + 20;
struct node {
    int cur;
    int tot;
} a[maxn];
struct dd {
    int use;
    int lef;
} dp[maxn][100 * 100 + 20];
void work() {
    int n;
    cin >> n;
    int has = 0;
    for (int i = 1; i <= n; ++i) {
        cin >> a[i].cur;
        has += a[i].cur;
    }
    for (int i = 1; i <= n; ++i) {
        cin >> a[i].tot;
    }
    memset(dp, -0x3f, sizeof dp);
    dp[0][0].use = 0;
    dp[0][0].lef = 0;
    for (int i = 1; i <= n; ++i) {
        for (int k = n; k >= 1; --k) {
            for (int j = 100 * 100; j >= a[i].tot; --j) {
                if (dp[k][j].use < dp[k - 1][j - a[i].tot].use + a[i].cur) {
                    dp[k][j].use = dp[k - 1][j - a[i].tot].use + a[i].cur;
                    dp[k][j].lef = j - dp[k][j].use;
                }
            }
        }
    }
    for (int k = 1; k <= n; ++k) {
        bool flag = false;
        int ans = inf;
        for (int j = 100 * 100; j >= 1; --j) {
            if (dp[k][j].use >= 0) {
                if (dp[k][j].lef >= has - dp[k][j].use) {
                    flag = true;
                    ans = min(ans, has - dp[k][j].use);
//                    cout << k << " " << has - dp[k][j].use << endl;
//                    return;
                }
            }
        }
        if (flag) {
            cout << k << " " << ans << endl;
            return;
        }
    }
}

int main() {
#ifdef local
    freopen("data.txt", "r", stdin);
//    freopen("data.txt", "w", stdout);
#endif
    work();
    return 0;
}
View Code

 

posted on 2016-12-27 16:34  stupid_one  阅读(212)  评论(0编辑  收藏  举报

导航