/* ======================================================================SCKNAP.c,David Pisinger,1996年1月,1999年4月修订====================================================================== *//*该代码解决了强相关背包问题*可以表述为**最大化\sum{j=1}^{n}(w{j}+k)x{j}*服从sum{j=1}^{n}w{j}x{j}\leqc*x{j}\in\{0,1\},j=1,\ldot,n**该代码的描述见以下文件:**D.Pisinger(1998)*“强相关背包问题的快速算法”*离散应用数学,89,197-212**当前代码是用ANSI-C编写的,并用*使用选项“-ansi-pedantic”的GNU-C编译器以及*使用选项“-Aa”(ansi标准)的HP-UX C编译器。**此文件包含带有原型的可调用例程scknap**int scknap(int n,int*w,int k,int c,int*x);**参数的含义如下:*n问题的大小,即要包装的物品数量。*w长度为n的整数数组,其中w[j]为*当j=0时,盒子j的重量,。。,n-1。*k表示“固定利润”的整数,因此*一个项目的利润是p[j]=w[j]+k。*c背包容量。*x长度为n的整数数组,其中返回时为x[j]*如果背包中应包含物品,则设置为1*否则为0。*scknap的返回值是最优目标值z。**(c)版权所有1999,**大卫·皮辛格*哥本哈根大学DIKU*帕肯大学1*丹麦哥本哈根**此代码可免费用于研究和学术目的*只有。*/#包括#包括#包括#包括#包括#包括#包括#包括/* ============================================================================================================================================ */#定义LOGSIZE 50000/*日志大小*/#定义SORTSTACK 200/*用于排序的堆栈深度*/#定义MINMED 100*/#定义TRUE 1#定义FALSE 0#定义LEFT 1#定义右侧2#定义PARTIATE 1#定义LEFTREC 2#定义RIGHTREC 3#定义SORTALL 4#定义SWAP(a,b){注册项t;t=*(a);*(a#定义NO(a,p)((int)((p)-(a)->fitem+1))#定义PTR(a,w)((a)->h+(w)+(a)->res))#定义WGT(a,i)((int)((i)-(a)->h-(a)->res))/* ======================================================================类型声明====================================================================== */typedef短布尔值;typedef int tyype;/*阶段数*/typedef短itype;/*物品重量*/typedef长型;/*利润或权重总和*//*项目记录*/typedef结构irec{类型w;/*重量*/整数*x;/*解决方案变量*/}项目;/*s-记录*/typedef结构{项目*s;/*[s,t]上定义了sum x{j}=\beta的解*/项目*s1;/*s的前一个值*/项目*p;/*求和x{j}=\beta+1的解定义在[s,t]上*/}srec;/*日志记录*/typedef结构{类型w;/*重量总和*/项目*i;/*已更改项*/}lrec;/*间歇式堆叠*/typedef结构{项目*f;/*间隔中的第一项*/项目*l;/*间隔中的最后一项*/}区间;/*所有问题信息*/typedef结构{类型n;/*有问题的项目数*/类型k;/*p[i]=w[i]+k*/项目*项目0;/*项目数组的开始*/项目*fitem;/*指向第一项的指针*/项目*litem;/*指向最后一项的指针*/项目*t;/*指向项“t”的指针*/项目*b;/*指向中断项的指针*/类型res;/*剩余容量*/项目*测试版;/*指向测试项目的指针*/类型wbeta;/*破碎物品重量*/类型rm;/*权重上限=wbeta+1*/it类型mw;/*最小重量*/类型c;/*背包容量*/类型z;/*现有解决方案*/类型wsumb;/*分解项目b的总重量*/类型psumb;/*b项利润总额*/stype dantzig;/*dantzig上限*/类型ub;/*电流上限*/类型maxwsum;/*测试项目的最大重量总和*/lrec*fset;/*日志的开始*/lrec*lset;/*日志结束*/lrec*当前;/*原木的当前位置*/srec*小时;/*s值表,s[h]=s[v]*/srec*h0;/*第一位置重量,s[h0]=s[c+1]*/srec*h1;/*所有权重的末尾,s[h1]=s[c+w{beta}+1]*/间隔*intv1,*intv2;/*间隔堆栈*/间隔*intv1b,*intv2b;项目*fpart;/*第一项,部分排序*/项目*lpart;/*最后一项,部分排序*/类型wfpart;/*第一部分排序的权重总和*//*调试*/长桌sz;/*表s[t]的大小,等于res+wb*/长totspace;/*原木尺寸*/长岩芯尺寸;/*堆芯尺寸*/布尔greedyok;/*贪婪的解决方案可以吗*/}allinfo;/* ======================================================================错误====================================================================== */void错误(char*str,…){va_list参数;va_start(args,str);vprintf(字符串,参数);printf(“\n”);va_end(参数);printf(“错误\n\n”);出口(-1);}/* ======================================================================帕洛克语====================================================================== */无效pfree(无效*p){如果(p==NULL)错误(“释放NULL”);自由(p);}void*palloc(长sz,长no){长*p,尺寸;尺寸=sz*否;如果(大小==0)大小=1;if(size!=(size_t)size)错误(“Alloc too big%ld”,size);p=malloc(大小);如果(p==NULL)错误(“无内存大小%ld”,大小);返回p;}/* ======================================================================推/弹出====================================================================== */void push(allinfo*a,int side,item*f,item*1){区间*pos;如果(l+1==f)返回;开关(侧){左侧病例:pos=a->intv1;(a->intv1)++;断裂;右案例: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;}/* ======================================================================中值的====================================================================== */项目*中位数(项目*f1,项目*l1,ntype s){/*求项目[f1,f1+s,f1+2s,…l1]的中位数r*//*并确保排序f1>=r>=l1*/注册类型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){如果(f->w>m->w)SWAP(f,m);如果(d>2){如果(m->w>l->w){SWAP(m,l);如果(f->w>m->w)SWAP(f,m);}}}如果(d<=3){r=*q;中断;}相对湿度=mw=m->w;i=f;j=l;用于(;;){当(i->w<mw)时,做{i+=s;};当(j->w>mw)时,做{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){寄存器itype-mw;登记项目*i、*j;注册类型wi;项目*m;整数d;d=l-f+1;如果(d<1)错误(“partsort中的负区间”);如果(d>最小){m=中值(f,l,MINMED);}其他{如果(d>1){m=f+d/2;如果(f->w>m->w)SWAP(f,m);如果(d>2){如果(m->w>l->w){SWAP(m,l);如果(f->w>m->w)SWAP(f,m);}}}}如果(d>3){mw=m->w;i=f;j=l;wi=ws;用于(;;){do{wi+=i->w;i++;}while(i->w<mw);在(j->w>mw)时执行{j--;};如果(i>j)断裂;SWAP(i,j);}如果(wi<=a->c){如果(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==PARTITATE)按下(a,RIGHT,i,l);如果(what==LEFTREC)按下(a,LEFT,i,l);如果(what==RIGHTREC)按下(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 sortmore(allinfo*a,int side,item**last){项目*f、*1;mw型;开关(侧){case LEFT:弹出(a,LEFT,&f,&l);部分排序(a,f,l,a->c+1,LEFTREC);*last=a->lpart;如果(*last>=a->b)错误(“bad last”);断裂;case RIGHT:弹出(a,RIGHT,&f,&l);部件排序(a,f,l,a->c+1,RIGHTREC);*last=a->lpart;断裂;}}/* ======================================================================分拣台====================================================================== */无效分拣(allinfo*a){项目*f、*1;mw型;while(a->intv1!=a->intv 1b){pop(a,LEFT,&f,&l);部分排序(a,f,l,0,SORTALL);}while(a->intv2!=a->intv2b){弹出(a,RIGHT,&f,&l);部分排序(a,f,l,0,SORTALL);}}/* ======================================================================最大重量====================================================================== */stype最大重量(allinfo*a,ntype beta){寄存器项*i,*m;寄存器类型wsum;wsum=0;对于(i=a->litem-beta+1,m=a->letem+1;i!=m;i++)wsum+=i->w;如果(wsum>a->c)返回a->c;if(wsum+beta*a->k>a->z){a->z=wsum+beta*a->k;对于(i=a->fitem,m=a->诉讼β+1;i!=m;i++)*(i->x)=0;对于(i=a->litem-beta+1,m=a->letem+1;i!=m;i++)*(i->x)=1;}返回wsum;}/* ======================================================================启发式的====================================================================== */布尔启发式(allinfo*a){登记项目*i、*j、*m、*b;注册类型r、d;项目*m1,*m2,*f,*l;/*m1:第一个排序项,m2:最后一个排序项*/r=a->c-a->wsumb;b=a->b;/*剩余间隙周围的隔板*/d=b->w-r;对于(i=a->fitem,j=a->b-1;i<=j;){*(i->x)=1;如果(i->w<d){i++;}其他{SWAP(i,j);j--;}}如果(r==0)返回TRUE;如果(i==b)返回FALSE;/*准备分区*/a->intv1=a->intv1b;推动(a,LEFT,a->fitem,i-1);推动(a,LEFT,i,b-1);/*现在运行项目*/m2=a->l部分;/*重要提示:在此之前无其他排序*/排序更多(a,LEFT,&m1);对于(j=b,m=a->litem+1;j!=m;j++){如果(j>m2)分拣更多(a,RIGHT,&m2);d=j->w-r;而(i->w<d){i++;如果(i>m1){如果(i>=b)返回FALSE;排序更多(a,LEFT,&m1);}}如果(i->w==d){*(i->x)=0*(j->x)=1;返回TRUE;}}返回FALSE;}/* ======================================================================定义解决方案====================================================================== */无效定义解决方案(allinfo*a){寄存器lrec*i,*m;寄存器srec*j,*k;注册项目*s、*f、*t;寄存器类型w,wm;类型z;/*找到最佳解决方案并存储信息*/对于(j=a->h0-1,w=0,f=a->item0;j->s==f;j--)w--;z=a->c+w+a->k*NO(a,a->beta);a->岩芯尺寸=(a->t-a->b);如果(a->res+a->wbeta>a->tablesz)a->tablesz=a->res+a->wbeta;如果(a->curr-a->fset>a->totspace)a->tosspace=a->cur-a->fset;/*检查是否最佳*/如果(z<=a->z)返回;/*找到了改进的解决方案*/对于(s=a->fitem,t=a->beta+1;s!=t;s++)*(s->x)=1;对于(s=a->beta+1,t=a->litem+1;s!=t;s++)*(s->x)=0;a->z=z;/*回溯解决方案*/wm=a->rm;对于(i=a->curr-1,m=a->fset-1,t=NULL;i!=m;i-){如果(i->w==w){s=i->i;*(s->x)=0;w+=s->w;/*删除个项目*/*(t->x)=1;w-=t->w;/*插入项目t*//*避免此组中的更多选择*/在(i->w!=wm)时执行{i--;};}如果(i->w==wm)t=i->i;}}/* ======================================================================迭代=================================================================*/void iterate(allinfo*a,item*t){登记项目*j,*n;寄存器srec*i,*k,*l,*m;寄存器类型w;srec*h,*h0;/*将权重t添加到带有beta项目的状态,从带有beta+1的状态中删除*/h0=a->h+a->res;对于(i=a->h,k=i+t->w,m=a->h0+a->wbeta-t->w,w=WGT(a,k);i!=米;i++、k++、w++){如果(i->s1>k->p){n=k->p-1;h=h0+w;k->p=i->s1;对于(j=k->p-1;j!=n;j--){l=h-j->w;如果(j>l->s)l->s=j;}}}}/* ======================================================================清理====================================================================== */空隙清理(allinfo*a){寄存器lrec*k,*l;寄存器srec*i,*m;寄存器类型w;k=a->电流;l=a->lset;/*负重块堆叠并旋转*/对于(i=a->h,m=a->h0,w=-a->res;i!=m;i++,w++){如果(i->s!=i->s1){k->i=i->s;k->w=w;k++;如果(k==l)断裂;i->s1=i->s;}}如果(k==l)错误(“满对数”);/*正权重保持不变*//*保存t的当前值*/k->w=a->rm;/*不匹配任何重量*/k->i=a->t;k++;如果(k==l)错误(“满对数”);a->电流=k;}/* ======================================================================初始化第一个====================================================================== */void initfirst(allinfo*a){寄存器srec*i,*m;注册项目*f、*f0、*j;寄存器类型w;lrec*k;int大小;/*初始化向量表*/a->fset=palloc(LOGSIZE,sizeof(lrec));a->curr=a->fset;a->lset=a->fset+LOGSIZE;a->rm=a->wbeta+1;/*初始化哈希表*/大小=a->res+a->wbeta+1;a->h=palloc(大小,sizeof(srec));a->h0=a->h+a->res+1;a->h1=a->h+大小;对于(i=a->h,m=a->h0,f=a->item0,f0=a->fitem;i!=m;i++){i->s=f;i->s1=f;i->p=f0;}对于(i=a->h0,m=a->h21,w=1;i!=m;i++,w++){而(f0->w<w)f0++;/*停止为w<=w{b}*/i->s=f;i->s1=f;i->p=f0;}/*将项目0的重量设置为0*/a->项目0->w=0;/*插入一个向量*/i=PTR(a,-a->res);i->s=a->beta+1;i->s1=a->β+1;k=a->电流;k->w=a->rm;k->i=a->beta;a->curr++;}/* ======================================================================复制问题====================================================================== */无效复制问题(项*f,项*1,int*w,int*x){注册项目*i,*m;寄存器int*ww,*xx;对于(i=f,m=l+1,ww=w,xx=x;i!=m;i++,ww++,xx++){i->w=*ww;i->x=xx;}}/* ======================================================================发现断裂====================================================================== */无效findbreak(allinfo*a){注册项目*i,*m;类型wsum,c;如果(a->c<0)错误(“负容量”);wsum=a->wfpart;c=a->c;/*注意:在启发式中x[i]设置为1*/对于(i=a->fpart;wsum<=c;i++)wsum+=i->w;i--;/*我们做得太过火了*/wsum-=i->w;如果(i>a->lpart)错误(“limits blow”);a->item0=a->fitem-1;a->b=i;a->β=i;a->wbeta=i->w;a->wsumb=wsum;a->psumb=wsum+a->k*NO(a,i-1);a->z=a->wsumb+a->k*NO(a,i-1);a->dantzig=a->psumb+((i->w+a->k)*(双)(a->c-a->wsumb))/i->w;a->ub=a->c+a->k*NO(a,i-1);/*初始化剩余矢量*/对于(m=a->litem+1;i!=m;i++)*(i->x)=0;}/* ======================================================================重磅====================================================================== */空配重(allinfo*a){注册项目*i,*m;注册类型mw;mw=a->fitem->w-1;对于(i=a->fitem,m=a->litem+1;i!=m;i++)i->w-=mw;a->mw=mw;}/* ======================================================================添加权重====================================================================== */无效附加重量(allinfo*a){注册项目*i,*m;注册类型mw;mw=a->mw;对于(i=a->fitem,m=a->litem+1;i!=m;i++)i->w+=mw;}/* ======================================================================scknap公司====================================================================== */外部int scknap(int n,int*w,int k,int c,int*x){allinfo a;项目*选项卡;interval*inttab;tyypeβ;/*为测试示例和两个边界项分配空间*/tab=(项目*)palloc(项目大小,n+1);a.fitem=标签[1];a.litem=&tab[n];复制问题(a.fitem、a.诉讼、w、x);a.n=n;交流=交流;a.k=k;a.greedyok=错误;a.tablesz=0;a.totspace=0;a.树脂尺寸=0;inttab=palloc(SORTSTACK,sizeof(interval));a.intv1=a.intv1b=inttab[0];a.intv2=a.intv2b=inttab[SORTSTACK-1];partsort(&a,a.fitem,a.litem,0,partitate);findbreak(&a);/*解决贪婪问题*/a.greedyok=启发式(&a);如果(a.greedyok){a.z=交流+交流*否(&a,a.b-1);}其他{排序(&a);a.res=交流-a.wsumb;对于(β=NO(&a,a.b)-1;β!=0; β-,a.res+=a.wbeta){a.beta=a.fitem+beta-1;a.wbeta=a.beta->w;a.maxwsum=最大重量(&a,beta);a.ub=a.maxwsum+a.k*beta;如果((a.beta+1)->w-a.beta->w>a.res)继续;如果(a.ub<=a.z)断裂;initfirst(&a);对于(a.t=诉讼+β;a.t=诉讼;a.t++){如果(a.t->w>a.res+a.wbeta)断裂;迭代(&a,a.t);清理(&a);如果((a.h0-1)->s!=a.第0项)断裂;}定义解析(&a);pfree(a.h);pfree(a.fset);}}pfree(选项卡);返回a.z;}