多重背包【优先级队列写法】

   题目链接: http://poj.org/problem?id=3900
   首先声明: 本算法不能过这个题,以免耽搁大家的宝贵时间,特此申明!!!不过思想还是挺好的,个人感觉。。。。。
   在很久开始学习多重背包的时候,就考虑过,如果背包容量过大(物品'体积'也比较大),而物品的数量过少(当然暴力无法解决的)的时候我们是否还是可以用常规的方法写?比如背包容量为10^9次方,那么常规的方法内存不足!当我们回过头来看待的时候,其实背包容量很多的情况是无法达到要求的。比如物品为10000,200000的无穷背包,背包容量为1000000000,我们可以看到200001这个背包容量永远都无法达到的!所以我们是否想过把这些点都"压缩掉",当然可以。最常规想到的办法是 链表,因为链表的插入和删除时O(1)的时间复杂度,遍历是无法改变的!但是,去掉链表中的重复元素又是一个难题了,解决办法可以是两个指针。当插入一个物品到链表中的时候,从链表中的最后一个元素遍历(开始两个指针都指向最后一个元素),当我们扫描的时候,那么借助于前面一个指针的元素加上本物品的“体积”一定在第二个指针前面(假定链表有序(在插入的时候我们也会保证元素有序))(读者可以自行证明一下)。去重也达到了,不过有点复杂,读者可以实现以下。
    今天主要的重点是讲 重背包的优先级队列写法:
   其实思想还是和常规的方法差不多,只是用了两个优先级队列维护背包(物品“体积”大的优先)。首先建立两个优先队列,一个是当前背包状态的队列,一个是要被更新的队列(empty)。当我们要插入一个物品的时候,我们可以遍历第一个队列,然后借助本物品加入第二个队列。读者可以好好想想。。。。但是现在又有一个问题了,如果我们对队列里面的元素不去重的话,那么我们队列的内存和时间复杂度都会超。那么我们怎么解决重复的问题呢???可以自己写优先队列,然后用映射的对应关系来更新队列,自己取决是否覆盖还是丢弃。当然用这种方法不一定是最好的,我相信这一定不是最差的,可以值得我们好好的研究。。。
下面是具体算法:
#include
#include
#define N 20
using namespace std;

typedef struct data
{
int w,c;
}Data;

Data st[2][1000005];

int n,m,W[N],ansW,ansC,C[N];

map ff;
int now,pre,len[2],ans,total,anstotal;

void Exchange()
{
now=1-now;
ans=1-ans;
pre=1-pre;
}

int get(data *p,int &le)
{
if(le<=1)return -1;//取出的时候不是优先队列//优先队列起不到作用
ansW=p[--le].w;
ansC=p[le].c;
return 1;
}

void Insert(data *p,int &le,int w,int c)
{
p[le].w=w;
p[le].c=c;
int Pre,Now=le++;
while((Now>>1)>0)
{
Pre=Now>>1;
if(p[Now].w>p[Pre].w)
{
Data h=p[Now];
p[Now]=p[Pre];
p[Pre]=h;
ff[p[Now].w]=Now;
ff[p[Pre].w]=Pre;
Now=Pre;
}
else break;
}
}

void Check(int w,int c)//更新
{
int x,total=0;
ff.clear();
while(get(st[pre],len[pre])!=-1)
{
x=ansW+w;
int id=ff[x];
Insert(st[now],len[now],ansW,ansC);
if(id!=0)
{
if(st[now][id].c
}
else
{
if(ansW+w>m)continue;
Insert(st[now],len[now],ansW+w,ansC+c);
}
}
}
void make()
{
now=0;
pre=1;
ans=0;
st[0][1].w=0;
st[0][1].c=0;
len[0]=2;
len[1]=1;
int i,k,j;
total=0;
anstotal=0;
for(i=1;i<=n;i++)
{
scanf("%d",&W[i]);
total+=W[i]*i;
}
for(i=1;i<=n;i++)
{
scanf("%d",&C[i]);
anstotal+=C[i]*i;
}
if(total<=m)
{
printf("%d\n",anstotal);
return;
}
for(i=1;i<=n;i++)
{
k=1;
j=i;
while(k<=j)
{
j-=k;
Exchange();
Check(k*W[i],k*C[i]);
k*=2;
}
if(j)
{
Exchange();
Check(j*W[i],j*C[i]);
}
}
int Max=-1;
while(get(st[ans],len[ans])!=-1)
{
if(Max
}
printf("%d\n",Max);
}

int main()
{
int t=1;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&m);
make();
}
return 0;
}

实践证明这个是不实际的!!!!请读者思考

你可能感兴趣的:(变异算法)