zoukankan      html  css  js  c++  java
  • 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;
    }
    
  • 相关阅读:
    LeetCode偶尔一题 —— 617. 合并二叉树
    《剑指offer》 —— 链表中倒数第k个节点
    《剑指offer》 —— 青蛙跳台阶问题
    《剑指offer》—— 二维数组中的查找
    《剑指offer》—— 替换空格
    《剑指offer》—— 合并两个排序的链表
    《剑指offer》—— 礼物的最大价值
    生成Nuget 源代码包来重用你的Asp.net MVC代码
    Pro ASP.Net Core MVC 6th 第四章
    Pro ASP.NET Core MVC 6th 第三章
  • 原文地址:https://www.cnblogs.com/onionQAQ/p/10754152.html
Copyright © 2011-2022 走看看