超大01背包(hdu 5887)

针对大规模数据集的01背包问题,通过使用map替代数组存储可达状态并结合优先队列优化,实现内存高效利用,确保在限定时间内获取最优解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值