P2340 奶牛会展(状压dp)

P2340 奶牛会展

题目背景

奶牛想证明它们是聪明而风趣的。为此,贝西筹备了一个奶牛博览会,她已经对N 头奶牛进行

了面试,确定了每头奶牛的智商和情商。

题目描述

贝西有权选择让哪些奶牛参加展览。由于负的智商或情商会造成负面效果,所以贝西不希望出展奶牛的智商之和小于零,或情商之和小于零。满足这两个条件下,她希望出展奶牛的智商与情商之和越大越好,请帮助贝西求出这个最大值。

输入输出格式

输入格式:

 

• 第一行:单个整数N,1 ≤ N ≤ 400

• 第二行到第N + 1 行:第i + 1 行有两个整数:Si 和Fi,表示第i 头奶牛的智商和情商,−1000 ≤ Si; Fi ≤ 1000

 

输出格式:

 

输出格式

• 单个整数:表示情商与智商和的最大值。贝西可以不让任何奶牛参加展览,如果这样做是最好的,输出0

 

输入输出样例

输入样例#1:
5
-5 7
8 -6
6 -3
2 1
-8 -5
输出样例#1:
8

说明

选择第一头,第三头,第四头奶牛,智商和为−5+6+2 = 3,情商和为7−3+1 = 5。再加

入第二号奶牛可使总和提升到10,不过由于情商和变成负的了,所以是不允许的

分析

特殊的0-1背包。常见的想法就是设 f(i, j) 表示 i, j 能否到达,对这道题来说数据太大,会超时、超空间,因为其实根本就没有这么多状态,很多状态都是无效的。但是,数组的下标和值都可以存储信息,所以我们可以把智商和情商分别存到到下标和值上,这样就完美解决了空间的问题,也算是一种状压 DP。

最后要注意:C++ 中没有负数下标,所以我们需要把 dp 数组平移 M 位。

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<cstring>
 4 
 5 using namespace std;
 6 const int N = 405,M = 400000;
 7 int f[M*2+100];    //f下标存iq,值存eq; 
 8 int iq[N],eq[N];
 9 int n,ans;
10 
11 int main()
12 {
13     scanf("%d",&n);
14     for (int i=1; i<=n; ++i)
15         scanf("%d%d",&iq[i],&eq[i]);
16     memset(f,-0x3f,sizeof(f));
17     f[M] = 0;
18     for (int i=1; i<=n; ++i)
19     {
20         if(iq[i] > 0) //根据iq[i]的符号确定循环方向,消除后效性
21             for (int j=M*2; j>=iq[i]; --j)
22                 f[j] = max(f[j],f[j-iq[i]]+eq[i]);
23         else 
24             for (int j=0; j<=M*2+iq[i]; ++j)
25                 f[j] = max(f[j],f[j-iq[i]]+eq[i]);
26     }
27     for (int i=1; i<=M; ++i)
28         if(f[i+M] >= 0)
29             ans = max(ans,f[i+M]+i); //i是智商,f[i+M]情商 
30     printf("%d",ans);
31     return 0;
32 }

 

转载于:https://www.cnblogs.com/mjtcn/p/6914393.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值