/* ======================================================================BOUKNAP.c,David Pisinger 1993年,1994年,1999年修订====================================================================== *//*这是与论文相对应的C代码:**D.皮辛格*有界背包问题的一个极小算法*收录:E.Balas,J.Clausen(编辑):整数规划和*组合优化,第四届IPCO会议。*《计算机科学讲稿》,柏林施普林格,92095-109(1995)。**有关该项目的更多详细信息,请参阅**D.皮辛格*背包问题的算法*哥本哈根大学DIKU 95/1号报告*帕肯大学1*DK-2100哥本哈根**该算法可用于学术、非商业目的*只有。*-------------------------------------------------------------------*当前代码是一个可调用例程,用于求解一个有界*表格上的背包问题:**最大化\sum{j=1}^{n}p{j}x{j}*服从sum{j=1}^{n}w{j}x{j}\leqc*x_{j}\in\{0,…,m_{j{}\},j=1,\ldots,n**布纳普算法称为**z=布纳普(n,p,w,m,x,c)**其中p[]、w[]、m[]、x[]是整数数组。最佳目标*值以z返回,x[]给出解向量。*如果您的算法需要不同的接口,bounnap*可以很容易地适应您自己的数据结构,因为所有表*复制到内部表示。**不同类型的定义如下:**它的类型应该足够大,以容纳利润或重量*类型应足以容纳利润/权重的总和*ptype应该包含类型和itype的产品**该代码已在hp9000/735上测试,符合*ANSI-C标准。**错误和问题是指:**David Pisinger,副教授*哥本哈根大学DIKU,*Parken 1大学,*DK-2100哥本哈根。*电子邮件:pisinger@diku.dk*传真:+45 35 32 14 01*//* ======================================================================定义====================================================================== */#包括#包括#包括#包括#包括#包括#包括#包括#包括/* ============================================================================================================================================ */#定义SYNC 5/*何时切换到箱子中的线性扫描*/#定义SORTSTACK 200/*qsort中使用的堆栈深度*/#定义MINMED 100/*如果尺寸较大,则在qsort中查找准确的中位数*/#定义TRUE 1#定义FALSE 0#定义LEFT 1#定义右侧2#定义PARTIATE 1#定义SORTALL 2#定义MAXV(8*sizeof(vtype))/*长整数中的位数*/#定义PMAX 1/*全球最有效项目的利润*/#定义WMAX 0/*世界上最有效项目的重量*/#定义PMIN 0/*世界上效率最低的项目的利润*/#定义WMIN 1/*世界上效率最低的物品的重量*/#定义DET(a1,a2,b1,b2)((a1)*(ptype)(b2)-(a2)*(pt类型)(b1))#定义SWAP(a,b){注册项t;t=*(a);*(a#定义NO(a,p)((int)((p)-(a)->fitem+1))#定义N(a,p)((int)((p)-(a)->d.fset))#定义尺寸(a)((int)(((a)->lset+1)-(a)->fset))/* ======================================================================类型声明====================================================================== */typedef int布尔值;typedef int tyype;/*状态或项目数*/typedef短itype;/*项目利润和权重*/typedef短mtype;/*每个项目的数量*/typedef长型;/*重量总和*/typedef双ptype;/*产品类型(足够精度)*/typedef无符号长ltype;/*正大数*/typedef无符号长vtype;/*向量的表示*//*项目记录*/typedef结构irec{t类型p;/*利润*/itype w;/*重量*/m类型m;/*选择的数量*/整数*x;/*解决方案变量*/}项目;/*i堆栈*/typedef结构{项目*f;项目*1;}区间;/*动态规划中的状态*/typedef结构pv{柱头石膏;类型wsum;vtype vect;}国家;/*状态集*/typedef结构集{典型尺寸;/*设置大小*/状态*fset;/*集合中的第一个元素*/状态*lset;/*集合中的最后一个元素*/}状态集;/*参考结构*/typedef结构{项目*i;/*项目类型已更改*/m类型号;/*+或-项目数*/}reftype;/*解决方案结构*/typedef结构{reftype列表[MAXV];类型pos;/*列表中的当前位置*/聚苯乙烯;/*解决方案的利润总额*/类型wsum;/*溶液的重量总和*/vtype vect;/*最优解向量*/项目*a;/*最佳堆芯起点*/项目*b;/*最佳堆芯末端*/}solstrct;typedef结构{/*所有问题信息*/类型n;/*项目数量*/项目*fitem;/*有问题的第一项*/项目*litem;/*问题的最后一项*/项目*ftouch;/*考虑减少的第一项*/项目*ltouch;/*考虑减少的最后一项*/项目*s;/*当前核心是[s,t]*/项目*t;/**/项目*b;/*中断项目*/项目*fpart;/*部分排序返回的第一项*/项目*lpart;/*部分排序返回的最后一项*/类型wfpart;/*重量总和达fpart*/项目*fsort;/*第一个排序项*/项目*lsort;/*最后排序的项目*/苯乙烯wfsort;/*达到fsort的重量总和*/苯乙烯c;/*电流容量*/类型cstar;/*原始容量*/类型z;/*当前解决方案*/类型zstar;/*最优解*/类型zwsum;/*zstar的权重和*/类型ps、ws、pt、wt;/*用于派生边界的项*/solstrct sol;/*当前解决方案*/solstrct optsol;/*最优解*/stype dantzig;/*dantzig上限*/类型ub;/*全局上限*/类型psumb;/*利润总额达到b*/类型wsumb;/*重量总和达到b*/boolean firsttime;/*用于恢复x*/布尔welldef;/*x是否定义良好*/状态集d;/*部分向量集*/区间*intv1,*intv2;间隔*intv1b,*intv2b;/*调试*/已检查布尔值;/*不同的计数器用于获得*/长迭代;/*有关程序的具体信息*/长期简化;长诱导;长期苦恼;长毛球;长brkill;长maxstage;长gmaxtages;长岩芯;长时间;}allinfo;typedef int(*funcptr)(常量无效*,常量无效*);/* ======================================================================错误====================================================================== */void错误(char*str,…){va_list参数;va_start(参数,字符串);vprintf(字符串,参数);printf(“\n”);va_end(参数);printf(“程序终止!!!\n\n”);出口(-1);}/* ======================================================================帕洛克语====================================================================== */void pfree(无效*p){如果(p==NULL)错误(“释放NULL”);自由(p);}void*palloc(长no,长recsize){ 长尺寸;字符*p;大小=否*大小;如果(大小==0)大小=1;if(size!=(size_t)size)错误(“Alloc too big%ld”,size);p=malloc(大小);如果(p==NULL)错误(“无内存大小%ld”,大小);返回p;}/* ======================================================================查找====================================================================== */状态*findvect(stype ws,状态*f,状态*l){/*找到向量i,使i->wsum<=ws<(i+1)->wsum*/状态*m;/*一个集合应该始终至少有一个向量*/如果(f>l)错误(“findvect:空集”);如果(f->wsum>ws)返回NULL;如果(l->wsum<=ws)返回l;而(l-f>同步){m=f+(l-f)/2;如果(m->wsum>ws){l=m-1;}其他{f=m;}}而(l->wsum>ws)l--;返回l;}/* ======================================================================推/弹出====================================================================== */void push(allinfo*a,int side,item*f,item*1){寄存器间隔*pos;开关(侧){左侧病例:pos=a->intv1;(a->intv1)++;断裂;case RIGHT:pos=a->intv2;(a->intv2)--;断裂;}如果(a->intv1==a->intv)错误(“间隔堆栈已满”);位置->f=f;位置->l=l;}void pop(allinfo*a,int side,item**f,item**l){寄存器间隔*pos;开关(侧){左案例:如果(a->intv1==a->intv 1b)错误(“左弹出”);(a->intv1)--;pos=a->intv1;断裂;case RIGHT:如果(a->intv2==a->intv 2b)错误(“弹出右侧”);(a->intv2)++;pos=a->intv2;断裂;}*f=位置->f*l=位置->l;}/* ======================================================================改进解决方案=================================================================*/无效改进解决方案(allinfo*a,state*v){如果(v->wsum>a->c)错误(“错误改进”);如果(v->psum<=a->z)错误(“没有改进的解决方案”);a->z=v->psum;a->zwsum=v->wsum;a->optsol=a->sol;a->optsol.psum=v->psum;a->optsol.wsum=v->wsum;a->optsol.vect=v->vect;a->optsol.a=a->s;a->optsol.b=a->t;}/* ======================================================================definesol公司====================================================================== */无效定义(allinfo*a){项目*f、*1、*i;m型;v类型j;触针psum、wsum、rem;整数k;if(a->第一次){a->zstar=a->z+a->psumb;a->gmaxstages=a->maxstages;a->firsttime=FALSE;}psum=a->optsol.psum;wsum=a->optsol.wsum;f=a->optsol.a;l=a->optsol.b;如果(a->optsol.a>a->optsol.b)错误(“找不到解决方案”);/*求解向量*/对于(k=0;k!=MAXV;k++){j=a->optsol.vect&(vtype)1<<k);i=a->optsol.list[k].i;m=a->optsol.list[k].no;如果(i==NULL)继续;如果(i<a->b){if(i>f)f=i;}否则{if如果(j){psum-=i->p*(苯乙烯)m;wsum-=i->w*(苯乙烯)m;*(i->x)+=m;}}a->welldef=(psum==0)&&(wsum==O);/*为下一轮比赛做准备*/if(!a->welldef){/*printf(“再次在集合中搜索]%d,%d[\n”,NO(a,f),NO(b,l))*/a->fsort=f;/*我们不能加减一,因为*/a->lsort=l;/*项目f的分数可能被忽略*/a->intv1=a->intv1b;a->intv2=a->intv 2b;a->c=wsum;a->z=psum-1;a->ub=psum;a->maxstages=0;/*如果找不到(不应该出现),则生成空溶液*/a->optsol.vect=0;a->optsol.a=a->b;a->optsol.b=a->b-1;}}/* ======================================================================中值的====================================================================== */项目*中位数(项目*f1,项目*11,类型s){/*求项目[f1,f1+s,f1+2s,…l1]的中位数r*//*并确保排序f1>=r>=l1*/寄存器ptype mp,mw;登记项目*i、*j;项目*f,*l,*k,*m,*q;类型n,d;静态项r;n=(l1-f1)/s;/*数值的数量*/f=f1;/*计算出的第一项*/l=f1+s*n;/*计算的最后一项*/k=l;/*保存的最后一个项目*/q=f+s*(n/2);/*中间值*/用于(;;){d=(l-f+s)/s;m=f+s*(d/2);如果(d>1){如果(DET(f->p,f->w,m->p,m->w)<0)SWAP(f,m);如果(d>2){如果(DET(m->p,m->w,l->p,l->w)<0){SWAP(m,l);如果(DET(f->p,f->w,m->p,m->w)<0)SWAP(f,m);}}}如果(d<=3){r=*q;中断;}r.p=mp=m->p;相对湿度=mw=m->w;i=f;j=l;用于(;;){当(DET(i->p,i->w,mp,mw)>0时,执行{i+=s;};当(DET(j->p,j->w,mp,mw)<0)时,执行{j-=s;};如果(i>j)断裂;SWAP(i,j);}如果((j<=q)&&(q<=i))中断;如果(i>q)l=j;否则f=i;}SWAP(k,l1);返回&r;}/* ======================================================================部分排序====================================================================== */void partsort(allinfo*a,item*f,item*1,stype ws,int what){寄存器ptype mp,mw;注册项目*i、*j、*m;寄存器ltype wi;整数d;d=l-f+1;如果(d<1)错误(“partsort中的负区间”);如果(d>最小){m=中位数(f,l,(int)sqrt(d));}其他{如果(d>1){m=f+d/2;如果(DET(f->p,f->w,m->p,m->w)<0)SWAP(f,m);如果(d>2){如果(DET(m->p,m->w,l->p,l->w)<0){SWAP(m,l);如果(DET(f->p,f->w,m->p,m->w)<0)SWAP(f,m);}}}}如果(d>3){mp=m->p;mw=m->w;i=f;j=l;wi=ws;用于(;;){执行{wi+=i->m*(类型)i->w;i++;},同时(DET(i->p,i->w,mp,mw)>0);在(DET(j->p,j->w,mp,mw)<0)时执行{j--;};如果(i>j)断裂;SWAP(i,j);}if(wi<=a->cstar){如果(what==SORTALL)部分排序(a,f,i-1,ws,what);如果(what==PARTIATE)按下(a,LEFT,f,i-1);部分排序(a,i,l,wi,what);}其他{如果(what==SORTALL)部分排序(a,i,l,wi,what);如果(what==PARTIATE)按下(a,RIGHT,i,l);部件排序(a,f,i-1,ws,what);}}if((d<=3)||(what==SORTALL)){a->fpart=f;a->lpart=l;a->wfpart=ws;}}/* ======================================================================合并====================================================================== */void合并(allinfo*a,item*h,mtype no){寄存器状态*i,*j,*k,*m;寄存器类型p,w;寄存器vtype mask0,mask1;状态*r1,*rm,*d;如果(a->d.size==0)返回;p=否*(苯乙烯)h->p;w=无*(苯乙烯)h->w;/*跟踪解向量*/a->溶胶pos++;如果(a->sol.pos==MAXV)a->sol_pos=0;mask1=((vtype)1<<a->sol.pos);mask0=~mask1;a->sol.list[a->sol.pos].i=h;a->sol.list[a->sol.pos].no=no;/*初始化限制*/d=palloc(2*a->d.size+1,sizeof(state));r1=a->d.fset;rm=a->d.lset;k=d;m=rm+1;k->psum=r1->psum-abs(p)-1;k->wsum=r1->wsum+abs(p)+1;m->wsum=rm->wsum+abs(w)+1;对于(i=r1,j=r1;(i!=m)||(j!=m;){如果(i->wsum<=j->wsum+w){如果(i->psum>k->psum){如果(i->wsum>k->wsum)k++;k->psum=i->psum;k->wsum=i->wsum;k->vect=i->vect&mask0;}i++;}其他{如果(j->psum+p>k->psum){如果(j->wsum+w>k->wsum)k++;k->psum=j->psum+p;k->wsum=j->wsum+w;k->vect=j->vect|mask1;}j++;}} pfree(a->d.fset);a->d.fset=d;a->d.lset=k;a->d.size=尺寸(&a->d);}/* ============================================================================================================================================ */void multiply(allinfo*a,item*h,itypex,int端){m型k;国家*非营利组织;如果(a->d.size==0)返回;对于(k=1;x!=0;k+=k){如果(k>x)k=x;合并(a,h,(side==LEFT?-k:k));x=k;}如果(a->d.size>a->maxstages)a->maxtages=a->d.size;a->芯径++;}/* =========================================================================simpreduce公司========================================================================= */void simpreduce(int side,item**f,item****l,allinfo*a){注册项目*i、*j、*k;寄存器ptype pb,wb;寄存器ptype q,r;如果(a->d.size==0){*f=*1+1;return;}如果(*1<*f)返回;pb=a->b->p;wb=a->b->w;q=DET(a->z+1,a->c,pb,wb);r=-DET(a->z+1-a->psumb,a->c-a->wsumb,pb,wb);i=*f;j=*l;if(侧面==左侧){k=a->fsort-1;而(i!=j+1){如果(DET(j->p,j->w,pb,wb)>r){SWAP(i,j);i++;/*不可行*/a->simpreduced++;}其他{SWAP(j,k);j——;k--;/*可行的*/}}*l=a->fsort-1*f=k+1;}其他{k=a->lsort+1;而(i!=j+1){如果(DET(i->p,i->w,pb,wb)<q){SWAP(i,j);j--;/*不可行*/a->simpreduced++;}其他{SWAP(i,k);i++;k++;/*可行的*/}}*f=a->lsort+1*l=k-1;}}/* ======================================================================拧紧====================================================================== */类型拧紧(allinfo*a,item*i,int-side){寄存器状态*j,*m;寄存器ptype p,w,z,c;寄存器类型d、h、mx;a->pitested+=i->m;如果(a->d.size==0){mx=0;}其他{if(侧面==右侧){p=a->ps;w=a->ws;d=-DET(i->p,i->w,p,w);如果(d==0),返回i->m;z=a->z+1;c=a->c;mx=(c-a->d.fset->wsum)/i->w;如果(mx>=i->m),则返回i->m;对于(j=a->d.fset,m=a->dlset+1;j!=m;j++){h=DET(j->psum-z,j->wsum-c,p,w)/d;如果(h>mx){mx=h;如果(mx>=i->m)返回i->m;}}}其他{p=a->pt;w=a->重量;d=DET(i->p,i->w,p,w);如果(d==0)返回i->m;z=a->z+1;c=a->c;mx=(a->d.lset->wsum-c)/i->w;如果(mx>=i->m),则返回i->m;对于(j=a->d.lset,m=a->dfset-1;j!=m;j--){h=DET(j->psum-z,j->wsum-c,p,w)/d;如果(h>mx){mx=h;如果(mx>=i->m)返回i->m;}}}}a->pikill+=i->m-mx;如果(mx==0)a->pireduced++;返回mx;}/* ======================================================================减少重置====================================================================== */无效还原集(allinfo*a){寄存器状态*i,*m,*k;寄存器ptype ps、ws、pt、wt、r;类型z,c;状态*r1,*rm,*v;项目*f、*1;如果(a->d.size==0)返回;/*初始化限制*/r1=a->d.fset;rm=a->d.lset;v=findvect(a->c,r1,rm);如果(v==NULL)v=r1-1;/*所有状态都不可行*/else{if(v->psum>a->z)改进解(a,v);}c=a->c;z=a->z+1;k=a->d.fset-1;/*展开core并选择ps、ws*/if(a->s<a->fsort){如果(a->intv1==a->intv 1b){ps=PMAX;ws=WMAX;}其他{弹出(a,LEFT,&f,&l);如果(f<a->ftouch)a->ftooch=f;ps=f->p;ws=f->w;/*默认设置:随机选择项目*/simpreduce(左,&f,&l,a);如果(f!=l+1){部分排序(a,f,l,0,SORTALL);a->fsort=f;ps=a->s->p;ws=a->s->w;}}}其他{ps=a->s->p;ws=a->s->w;}/*展开铁芯,选择pt、wt*/if(a->t>a->lsort){如果(a->intv2==a->intv 2b){pt=PMIN;wt=WMIN;}其他{弹出(a,RIGHT,&f,&l);如果(l>a->ltouch)a->ltooch=l;pt=1->p;wt=l->w;/*默认值:随机选择项目*/simpreduce(右,&f,&l,a);如果(f<=l){部分排序(a,f,l,0,SORTALL);a->lsort=l;pt=a->t->p;wt=a->t->w;}}}其他{pt=a->t->p;wt=a->t->w;}/*现在做减价*/r=DET(z,c,pt,wt);对于(i=r1,m=v+1;i!=m;i++){如果(DET(i->psum,i->wsum,pt,wt)>=r){k++;*k=*i;}}r=DET(z,c,ps,ws);对于(i=v+1,m=rm+1;i!=m;i++){if(DET(i->psum,i->wsum,ps,ws)>=r){k++;*k=*i;}}a->ps=ps;a->ws=ws;a->pt=pt;a->重量=重量;a->d.lset=k;a->d.size=尺寸(&a->d);}/* ======================================================================初始化第一个====================================================================== */void initfirst(allinfo*a,类型ps,类型ws){寄存器vtype i;状态*k;a->d.size=1;a->d.fset=palloc(a->d.size+1,sizeof(state));/*最后保留一个*/a->d.lset=a->d.fset;/*利润和重量是相对于psumb、wsumb计算的*/k=a->d.fset;k->psum=ps;k->wsum=ws;k->vect=0;/*初始化emty解决方案结构*/对于(i=0;i!=MAXV;i++)a->sol.list[i].i=NULL;a->sol.pos=MAXV-1;a->optsol.a=a->b;a->optsol.b=a->b-1;}/* ======================================================================发现断裂====================================================================== */无效findbreak(allinfo*a){注册项目*i,*m;寄存器ltype psum,wsum,c;寄存器类型x;psum=0;wsum=0;c=a->cstar;对于(i=a->fitem;wsum<=c;i++){*(i->x)=i->m;psum+=i->p*(类型)i->m;wsum+=i->w*(类型)i->m;}i——;/*我们走得太远了*/psum-=i->p*(苯乙烯)i->m;wsum-=i->w*(类型)i->m;a->fsort=a->fpart;a->lsort=a->lpart;a->ftouch=a->fpart;a->ltouch=a->lpart;a->b=i;a->psumb=psum;a->wsumb=wsum;a->dantzig=((c-wsum)*(ptype)i->p)/i->w;/*找到贪婪下限*/对于(i=a->b,m=a->litem;i<=m;i++){*(i->x)=0;if(wsum+i->w<=c){x=(c-wsum)/i->w;如果(x>i->m)x=i->m;psum+=i->p*(类型)x;wsum+=i->w*(类型)x;}}a->z=psum-1-a->psumb;a->zstar=-1;a->c=a->cstar-a->wsumb;}/* ======================================================================复制问题====================================================================== */无效复制问题(项*f,项*1,int*p,int*w,int*m,int*x){注册项目*i,*n;寄存器int*pp,*ww,*mm,*xx;pp=p;ww=w;毫米=米;xx=x;对于(i=f,n=l+1;i!=n;i++,pp++,ww++,mm++,xx++){i->p=*pp;i->w=*ww;i->m=*毫米;i->x=xx;}}/*======================================================================粗粗粗粗粗粗粗粗粗粗粗粗粗粗粗粗粗粗粗粗粗粗粗粗粗粗粗粗粗粗粗粗粗粗粗粗粗粗粗粗粗粗粗粗粗粗粗粗粗粗粗粗粗粗粗粗粗粗粗粗粗粗粗粗粗=================================================================*/stype bouknap(int n,int*p,int*w,int*m,int*x,int c){allinfo a;y型;项目*选项卡;interval*inttab;/*为测试示例和两个边界项分配空间*/tab=(item*)palloc(n,sizeof(item));a.fitem=&tab[0];a.litem=&tab[n-1];复制问题(a.fitem,a.litem,p,w,m,x);/*生成测试实例*/a.n=n;a.cstar=c;a.iterates=0;a.simpreduced=0;a.pireduced=0;a.pitested=0;a.pikill=0;a.brkill=0;a.maxstages=0;a.芯尺寸=0;inttab=palloc(SORTSTACK,sizeof(interval));a.intv1=a.intv1b=inttab[0];a.intv2=a.intv2b=inttab[SORTSTACK-1];a.fsort=a.litem;a.lsort=a.fitem;partsort(&a,a.fitem,a.litem,0,partitate);findbreak(&a);a.ub=a.dantzig;a.第一次=真;用于(;;){a.迭代++;a.s=a.b-1;a.t=a.b;initfirst(&a,0,0);还原集(&a);而((a.d.size>0)&&(a.z!=a.ub)){如果(a.t<=a.lsort){y=拧紧(&a,a.t,RIGHT);如果(y!=0)乘以(&a,a.t,y,RIGHT);(a.t)++;}reduceset(&a);如果(a.s>=a.fsort){y=拧紧(&a,a.s,LEFT);如果(y!=0)乘以(&a,a.s,y,LEFT);(a.s)--;}reduceset(&a);}pfree(a.d.fset);定义(&a);如果(a.welldef)破裂;}pfree(标签);pfree(inttab);返回a.zstar;}/* ======================================================================结束====================================================================== */