• POJ 1015 Jury Compromise (算竞进阶习题)


    01背包

    我们对于这类选或者不选的模型应该先思考能否用01背包来解。
    毫无疑问物体的价值可以看成最大的d+p值,那么体积呢?题目的另一个限制条件是d-p的和的绝对值最小,这启发我们把每个物体的d-p的值当作体积。

    可以尝试设计状态f[i, j, k]表示从前i个物品中选j个,体积是k的最大价值。
    同样的,我们可以用滚动数组的方法把第一维i去掉。
    那么得到状态转移方程:

    f[j, k] = max(f[j - 1, k - d[i] - p[i]] + d[i] + p[i], f[j, k])

    对于j这一维,用倒序即可保证状态的更新.

    但是这里的体积可能是负数,为了保证下标为正数,我们可以先整体右移下标的区间,最后从重心两边寻找最近点即可找到体积差最小的状态。

    #include <iostream>
    #include <cstdio>
    #include <vector>
    #include <cstring>
    #define INF 0x3f3f3f3f
    #define full(a, b) memset(a, b, sizeof a)
    using namespace std;
    typedef long long ll;
    inline int lowbit(int x){ return x & (-x); }
    inline int read(){
        int X = 0, w = 0; char ch = 0;
        while(!isdigit(ch)) { w |= ch == '-'; ch = getchar(); }
        while(isdigit(ch)) X = (X << 3) + (X << 1) + (ch ^ 48), ch = getchar();
        return w ? -X : X;
    }
    inline int gcd(int a, int b){ return a % b ? gcd(b, a % b) : b; }
    inline int lcm(int a, int b){ return a / gcd(a, b) * b; }
    template<typename T>
    inline T max(T x, T y, T z){ return max(max(x, y), z); }
    template<typename T>
    inline T min(T x, T y, T z){ return min(min(x, y), z); }
    template<typename A, typename B, typename C>
    inline A fpow(A x, B p, C lyd){
        A ans = 1;
        for(; p; p >>= 1, x = 1LL * x * x % lyd)if(p & 1)ans = 1LL * x * ans % lyd;
        return ans;
    }
    const int N = 305;
    int a[N], b[N], dp[N][8005];
    vector<int> p[N][8005];
    int main(){
    
        int n, m, _ = 0;
        while(~scanf("%d%d", &n, &m) && n && m){
            for(int i = 0; i <= N - 1; i ++)
                for(int j = 0; j < 1000; j ++)
                    p[i][j].clear();
            for(int i = 1; i <= n; i ++){
                int x = read(), y = read();
                a[i] = x - y, b[i] = x + y;
            }
            full(dp, 0xcf);
            int now = 20 * m; dp[0][now] = 0;
            for(int i = 1; i <= n; i ++){
                for(int j = m; j >= 1; j --){
                    for(int k = 2 * now; k >= a[i]; k --){
                        if(dp[j][k] < dp[j - 1][k - a[i]] + b[i]){
                            dp[j][k] = dp[j - 1][k - a[i]] + b[i];
                            p[j][k] = p[j - 1][k - a[i]];
                            p[j][k].push_back(i);
                        }
                    }
                }
            }
            int i = 0;
            for(; dp[m][i + now] < 0 && dp[m][now - i] < 0; i ++);
            int k = dp[m][i + now] > dp[m][now - i] ? i : -i;
            int sumd = (dp[m][now + k] + k) / 2, sump = (dp[m][now + k] - k) / 2;
            printf("Jury #%d 
    ", ++_);
            printf("Best jury has value %d for prosecution and value %d for defence:
    ", sumd, sump);
            for(int j = 0; j < p[m][now + k].size(); j ++){
                printf(" %d", p[m][now + k][j]);
            }
            printf("
    ");
        }
        return 0;
    }
    
  • 相关阅读:
    idea 设置注释
    SVN解决冲突
    mysql执行 sql文件遇到USING BTREE ) ENGINE=MyISAM DEFAULT CHARSET=utf8错误
    如何查看JDK以及JAVA框架的源码
    一道常被人轻视的前端JS面试题
    Js 常用调试的方法
    主要的Ajax框架都有什么?
    Ajax使用的五步法
    Java正则表达式
    查出在当天所处的日期区间的某些数据
  • 原文地址:https://www.cnblogs.com/onionQAQ/p/10754152.html
Copyright © 2020-2023  润新知