题目:http://acm.hdu.edu.cn/showproblem.php?pid=5887
题意:01背包,就是收集草药,每个收集和整理的过程需要时间,整理收集完一个草药会获得一定的分数,要求在限定时间内整理和收集的草药得到的分数最高,就是数据范围有点大,到10的9次方
题解:范围太大,不能用一般的数组存下,10的9次方,内存会爆,可以采用减少内存的办法,即是每次记录可以达到的重量,对于无法达到的不考虑,用map进行保存,用map代替数组,每次加入一个草药时遍历前草药得到的map,先考虑在前草药基础上的时间有没有超过最大时间,超了不计较,没超存到优先队列中(保证质量大的最先出队),同时进行一步优化,这个很重要,不然会超内存,要保证在当前情况下花费时间多的得到的分数不能比时间少的分数要少,少了就不考虑这种情况,直接考虑下一种,再遍历队列,从大到小遍历,以此保证每次都只加一次,变化map值,改变map时都要与此时的最大值对比,最后输出最大值。下面0ms过
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<map>
#include<string>
#include<algorithm>
#include<queue>
using namespace std;
map<int,long long> mp;
int w;
int n;
long long sum;
typedef struct
{
int w,v;
}Value;
Value value[150];
priority_queue<int> p;//保证大的数先出
bool compare(Value v1,Value v2)
{
return v1.w>v2.w;
}
int main()
{
while(~scanf("%d %d",&n,&w))
{
for(int i=1;i<=n;i++)
{
scanf("%d %d",&value[i].w,&value[i].v);
}
mp[0]=0;//初始化,时间为0时分数为0
sum=0;
sort(value+1,value+1+n,compare);
for(int i=1;i<=n;i++)//01背包模拟
{
if(value[i].v==0 || value[i].w>w) continue;
long long maxx=0;
for(map<int,long long>::iterator it=mp.begin();it!=mp.end();++it)//遍历前面的决策
{
int d=it->first;
if((long long)d+(long long)value[i].w<=(long long)w && maxx<=it->second+value[i].v){p.push(d+value[i].w);}
maxx=max(maxx,it->second+value[i].v);//重要,没有这个会超内存,保证时间增长的同时,分数也在增长
}
while(!p.empty())
{
int d=p.top();p.pop();
mp[d]=max(mp[d],mp[d-value[i].w]+value[i].v);
if(sum<mp[d]){sum=mp[d];}
}
}
mp.clear();
printf("%lld\n",sum);
}
return 0;
}