本人推荐的好题,以前写了一题是balance,然后脑筋不行,直接来了个3维的,写到一半直接放弃了。去网上学习了下,这题完全可以转换为2维的,只需要初始化的时将所有的值都编程负无穷。
题意:给你n头牛,每头牛都有对应的智商和情商,让你选择一些牛,使得最后情商与智商的和最大(并且2者分别之和都为非负)。
思路:肯定是01背包,但是这个维数的转换是必须的,还应注意到这里面的值有正负2种,负的需要从小到大,正的大到小就ok,这里需要用到一个优化,一直记录现在的2个端点值。然后2维遍历的时候只需要遍历这个范围就行了。(有负值,则需要弄个转换点,使其全为正的)。
状态转移方程:dp[j+to] = max(dp[j+to],dp[j+to-arr1[i]]+arr2[i]);
#include<cstdio>
#include<cstring>
#include<iostream>
#define N 101
#define to 100000
#define MAXN 200001
#define INF 0x3f3f3f3f
#define max(a1,b1) (a1)>(b1)?(a1):(b1)
#define min(a1,b1) (a1)>(b1)?(b1):(a1)
using namespace std;
int arr1[N],arr2[N],n,dp[MAXN];
void solve()
{
for(int i=0;i<MAXN;++i)
dp[i] = -INF;
dp[to] = 0;
int l = 0,r = 0;
for(int i=1;i<=n;++i)
{
l = min(l,arr1[i]+l);
r = max(r,arr1[i]+r);
if(arr1[i]>0)
{
for(int j=r;j>=l;--j)
{
dp[j+to] = max(dp[j+to],dp[j+to-arr1[i]]+arr2[i]);
}
}
else
{
for(int j=l;j<=r;++j)
dp[j+to] = max(dp[j+to],dp[j+to-arr1[i]]+arr2[i]);
}
}
int ans = 0;
for(int i=0;i<=r;++i)
if(dp[i+to]>=0)
ans = max(ans,dp[i+to]+i);
cout<<ans<<endl;
}
int main(void)
{
while(cin>>n)
{
for(int i=1;i<=n;++i)
{
scanf("%d %d",arr1+i,arr2+i);
}
solve();
}
return 0;
}
本文介绍了一道关于牛的情商与智商组合问题的算法解决思路,通过将三维问题转化为二维01背包问题,并采用端点值优化技巧来提高效率。
914

被折叠的 条评论
为什么被折叠?



