題目: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;
}