hiho刷题日记——第六天01背包

来源:互联网 发布:淘宝试衣间在哪 编辑:程序博客网 时间:2024/05/21 09:06

简单的01背包问题,简单的说就是将已有的资源发挥出最大的价值。


每组测试数据的第一行为两个正整数N和M,表示奖品的个数,以及奖券数。

接下来的N行描述每一行描述一个奖品,其中第i行为两个整数need(i)和value(i),意义如前文所述。

测试数据保证

对于100%的数据,N的值不超过500,M的值不超过10^5

对于100%的数据,need(i)不超过2*10^5, value(i)不超过10^3


直接动态规划

定义int f(int n,int m)为 从第n个物品开始考虑,在还有m个资源的情况下能发挥的最大价值。

则有:

int f(int n,int m)
{
if(n==N) return 0;

int t1=f(n+1,m);
int t2=0;
if(m>=need[n]) t2=f(n+1,m-need[n])+value[n]; //唯一需要注意的就是当前资源足够时,才能发挥对应的价值。有m>=need[n]

return t1>t2?t1:t2;
}

以上代码确实可以解决这个01背包问题。

但是以上代码的运算速度太慢。

而且不能用一般的记忆化,因为所需空间(500*100000*4b)太大。

若将选择考虑顺序倒过来,考虑到在计算的过程中有一下情况:

为求f(n,m) 就得求得 f(n-1,m)和f(n-1,m-need[n])+value[n]。

若当前记录下f(n,m),在求f(n+1,m)的时候,f(n-1,m)和f(n-1,m-need[n])的值就用不着了。

所以用来做记忆化的数组就可以把n这个参数去掉,只需要一维就够了。int ans[M+1];

for(int n=0;n<N;n++)
for(int i=M;i>=need[n];i--) 
{
int t1=ans[i];
int t2=ans[i-need[n]]+value[n];
ans[i]=t1>t2?t1:t2;
}


全代码:

#include<cstdio>
#include<cstring>
using namespace std;


int N,M;
int need[501],value[501];
int ans[100001];


int f()
{
for(int n=0;n<N;n++)
for(int i=M;i>=need[n];i--) 
{
int t1=ans[i];
int t2=ans[i-need[n]]+value[n];
ans[i]=t1>t2?t1:t2;
}
return ans[M];
}


int main()
{
memset(ans,0,sizeof(ans));
scanf("%d%d",&N,&M);
for(int i=0;i<N;i++)
scanf("%d%d",&need[i],&value[i]);

printf("%d",f());

return 0;
}

0 0