zoukankan      html  css  js  c++  java
  • C. Dima and Salad 背包好题

    http://codeforces.com/contest/366/problem/C

    在n个物品中选出若干个,使得sum(a[i]) = k * sum(b[i])

    把问题转化一下就是,求sum(a[i] - k * b[i]) = 0的最大的a[i],这个时候已经把a[i]作为价值了

    那么怎么去求呢?

    一开始因为a[i] - k * b[i]有负数,那么需要fix值,fix = 1000

    我只设了dp[v]表示产生这个和值时的最大价值。那么如果能产生这个v值,就需要这个v值能整除fix。因为sigma(a[i] - k * b[i])=0

    那么这个v值其实就是若干个fix值相加而已。比如-1,fix后是999。。1,fix后是1001,相加是2000

    所以只有v % fix == 0的才能作为贡献。但是有bug。因为你不知道它是多少个数相加得到的v。如果是5个数得到的v,那么需要这个v要整除5 * fix才可以,所以我就用了dp[i][j]表示选了i个数产生j的最大价值。但是这样转移是1e9的,但是水过去了。

    #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;
    int a[maxn], b[maxn];
    struct node {
        int w, val;
    }c[maxn];
    const int fix = 1000;
    int dp[100 + 2][1099 * 100 + 20];
    void work() {
        int n, k;
        cin >> n >> k;
        int tot = 0;
        for (int i = 1; i <= n; ++i) cin >> a[i];
        for (int i = 1; i <= n; ++i) {
            cin >> b[i];
            c[i].w = a[i] - k * b[i] + fix;
            c[i].val = a[i];
            tot += c[i].w;
        }
        memset(dp, -0x3f, sizeof dp);
    //    cout << -inf << endl;
        cout << dp[0][0] << endl;
        dp[0][0] = 0;
        for (int i = 1; i <= n; ++i) {
            for (int j = i; j >= 1; --j) {
                for (int k = tot; k >= c[i].w; --k) {
                    dp[j][k] = max(dp[j][k], dp[j - 1][k - c[i].w] + c[i].val);
                }
            }
        }
        int ans = -1;
        for (int i = 1; i <= n; ++i) {
            for (int j = i * fix; j <= tot; j += fix) {
                ans = max(ans, dp[i][j]);
            }
        }
        cout << ans << endl;
    }
    
    int main() {
    #ifdef local
        freopen("data.txt", "r", stdin);
    //    freopen("data.txt", "w", stdout);
    #endif
        IOS;
        work();
        return 0;
    }
    View Code

    所以这个是二维费用背包问题。

    5 9
    100 100 100 100 100
    100 100 100 100 100

    然后这题的正解因该是,分开dp,就是一样的转移问题是a[i] - k * b[i]

    然后这些东西有正有负,那么就分开吧,dpup[v]表示整数那堆数,产生v这个数字的最大价值。

    那么需要dpup[v] + dpdown[v]

    注意有0的情况,0要单独处理一下,因为可能dpup[0]有值,但是dpdown[0]是-inf。

    #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;
    int a[maxn];
    int b[maxn];
    int c[maxn];
    int dpup[100 * 1000 + 20];
    int dpdown[100 * 1000 + 20];
    void work() {
        int n, k;
        cin >> n >> k;
        int tans = 0;
        int tot = 100 * 1000;
        for (int i = 1; i <= n; ++i) {
            cin >> a[i];
        }
        for (int i = 1; i <= n; ++i) {
            cin >> b[i];
            c[i] = a[i] - k * b[i];
            if (c[i] == 0) {
                tans += a[i];
            }
        }
        memset(dpup, -0x3f, sizeof dpup);
        memset(dpdown, -0x3f, sizeof dpdown);
    //    cout << dpup[1] + dpdown[1] << endl;
        dpup[0] = dpdown[0] = 0;
        for (int i = 1; i <= n; ++i) {
    //        if (c[i] == 0) continue;
            if (c[i] > 0) {
                for (int j = tot; j >= c[i]; --j) {
                    dpup[j] = max(dpup[j], dpup[j - c[i]] + a[i]);
                }
            } else {
                c[i] = -c[i];
                for (int j = tot; j >= c[i]; --j) {
                    dpdown[j] = max(dpdown[j], dpdown[j - c[i]] + a[i]);
                }
            }
        }
        int ans = -1;
        for (int i = 1; i <= tot; ++i) {
            ans = max(ans, dpup[i] + dpdown[i]);
        }
        if (tans != 0) ans = max(tans, ans);
        cout << ans << endl;
    }
    
    int main() {
    #ifdef local
        freopen("data.txt", "r", stdin);
    //    freopen("data.txt", "w", stdout);
    #endif
        IOS;
        work();
        return 0;
    }
    View Code
  • 相关阅读:
    Mysql数据库常用的命令 数据备份 恢复 远程
    A Tour of Go Images
    A Tour of Go Exercise: HTTP Handlers
    A Tour of Go Web servers
    A Tour of Go Exercise: Errors
    A Tour of Go Errors
    A Tour of Go Interfaces are satisfied implicitly
    A Tour of Go Interfaces
    A Tour of Go Methods with pointer receivers
    A Tour of Go Methods continued
  • 原文地址:https://www.cnblogs.com/liuweimingcprogram/p/6237557.html
Copyright © 2011-2022 走看看