• 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
  • 相关阅读:
    js控制两个日期相减
    下拉框只显示最初下拉框中的值和json返回array的交集
    js来进行字符串的转化和小数点后的截取
    js来实现popup的生成,带钟罩,可移动popup,点击body可自动消失
    css块居中
    響應式設計佈局
    pc端手機端自適應佈局方案
    pc端常規頁面實現
    pc端前端和手機端區別
    js字符串轉數組,數組轉字符串
  • 原文地址:https://www.cnblogs.com/liuweimingcprogram/p/6226415.html
Copyright © 2020-2023  润新知