• POJ 2184 Cow Exhibition【01背包+负数(经典)】


    POJ-2184
    【题意】:
    有n头牛,每头牛有自己的聪明值和幽默值,选出几头牛使得选出牛的聪明值总和大于0、幽默值总和大于0,求聪明值和幽默值总和相加最大为多少。
    【分析】:变种的01背包,可以把幽默度看成体积,智商看成价值,那么就转换成求体积和价值都为正值的最大值的01背包了。
    以 TS 作为体积,TF作为价值,在保证体积、价值非负的情况下,求解 sum,取其所有情况的最大值。
    难点:
    1)体积出现负数,将区间改变 [-100000, 100000] ---> [0, 200000]。
    (注意此时始点 dp[100000], [0, 100000)表示 TS 为负,(100000, 200000]表示 TS 为正)
    2)状态转移时,对于 smartness 出现负数的处理
    (二维更好理解一些,但是若写成一维,则注意内层循环的循环顺序(思想同“背包九讲”里的“优化空间”的方法))
    (在我看来:关键是对状态转移方程的理解程度,知道所求值是依赖谁求出来的,在一维数组中各个值的位置又在哪里)
    3)千万注意初始化,因为要保证“必须把背包装满”。
    【精彩讲解】:
    poj 2184解题报告(详细)
    POJ 2184 Cow Exhibition(0-1背包)

    #include<cstdio>
    #include<string>
    #include<cstdlib>
    #include<cmath>
    #include<iostream>
    #include<cstring>
    #include<set>
    #include<queue>
    #include<algorithm>
    #include<vector>
    #include<map>
    #include<cctype>
    #include<stack>
    #include<sstream>
    #include<list>
    #include<assert.h>
    #include<bitset>
    #include<numeric>
    #define debug() puts("++++")
    #define gcd(a,b) __gcd(a,b)
    #define lson l,m,rt<<1
    #define rson m+1,r,rt<<1|1
    #define fi first
    #define se second
    #define pb push_back
    #define sqr(x) ((x)*(x))
    #define ms(a,b) memset(a,b,sizeof(a))
    #define sz size()
    #define be begin()
    #define pu push_up
    #define pd push_down
    #define cl clear()
    #define lowbit(x) -x&x
    #define all 1,n,1
    #define rep(i,n,x) for(int i=(x); i<(n); i++)
    #define in freopen("in.in","r",stdin)
    #define out freopen("out.out","w",stdout)
    using namespace std;
    typedef long long LL;
    typedef unsigned long long ULL;
    typedef pair<int,int> P;
    const int INF = 0x3f3f3f3f;
    const LL LNF = 1e18;
    const int maxn =  1e5 + 5;
    const int maxm = 1e6 + 10;
    const double PI = acos(-1.0);
    const double eps = 1e-8;
    const int dx[] = {-1,1,0,0,1,1,-1,-1};
    const int dy[] = {0,0,1,-1,1,-1,1,-1};
    const int mon[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    const int monn[] = {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    /*
    5
    -5 7
    8 -6
    6 -3
    2 1
    -8 -5
    */
    int n;
    #define S 100000
    #define M 200000
    int a[105],b[105];
    int dp[200050];
    int main()
    {
        while(cin>>n)
        {
            for(int i=1; i<=n; i++)
                scanf("%d%d",&a[i],&b[i]);
            memset(dp,-INF,sizeof(dp));   //初始化为极小值
            dp[S]=0;  //100000代替0,去除负数
            for(int i=1; i<=n; i++)
            {
                if(a[i]>0)  //大于0,从右到左常规推导
                {
                    for(int j=M; j>=a[i]; j--)
                            dp[j]=max(dp[j],dp[j-a[i]]+b[i]);
                }
                else   //小于0,则需要从左到右推导
                {
                    for(int j=0; j-a[i]<=M; j++)
                            dp[j]=max(dp[j],dp[j-a[i]]+b[i]);
                }
            }
            int sum=0;
            for(int i=S; i<=M; i++) //i保证智慧>=0 ,而dp【i】保证幽默>=0
                if(dp[i]>=0)     //智慧与幽默都必须大于0
                    sum=max(sum,dp[i]+i-S);
            printf("%d
    ",sum);
        }
        return 0;
    }
    /*
    s[i] > 0,5-s[i] 很明显是小于 5 的,此时,dp[5-s[i]] 保存的还是 上一个状态 的值,所以我们可以放心大胆的用。
    然后是判断条件,dp[v-s[i]]>inf,记得一开始我们把表示智力值总和的数组的初始化为inf吗?如果,dp[v-s[i]]<=inf,这意味着没有这个智力值没有用到,也就是dp[v] 这个是没有dp[v-s[i]]这个状态,既然没有我们就无视罗。
    */
    
  • 相关阅读:
    内存区间poj 1840
    旋转实现iOS(iPhone/iPad) 屏幕旋转响应函数的缺点与窗口大小位置调整,以及解决办法
    文件模式JAVASE16IO流_3
    配置修改postgresql streaming replication
    查看字段postgresql pg_buffercache
    窗体方法VB.NET设置控件和窗体的显示级别
    流量最小HDU 3491 最小割
    方法返回javascript学习实录 之二(数组操作等等utils) 刘啸尘
    配置路由器静态路由配置
    任务问题Oracle 技术支持之现场优化的思维路径
  • 原文地址:https://www.cnblogs.com/Roni-i/p/9047389.html
Copyright © 2020-2023  润新知