1 / 18

算法设计与分析 第三章 动态规划 - 背包问题

算法设计与分析 第三章 动态规划 - 背包问题. 杨圣洪. 最化算法: 动态规划 基本步骤. 找出 最优解 的性质,并刻划其 结构特征。 递归定义最优值。有难度。 以 自底向上 的方式计算出 最优值 。 非递归 根据计算最优值时得到的信息, 构造 最优解。! 第 (1) 为 整体 最优是否有 局部 最优。. 3.10 0-1 背包问题. 给定 n 种 物品 和一 背包 。物品 i 的 体积 是 wi ,其价值为 vi ,背包的 容量 为 C 。问应如何选择装入 背包 的 物品 ,使得装入背包中物品的 总价值 最大 ? 0-1 背包 问题是一个

toni
Download Presentation

算法设计与分析 第三章 动态规划 - 背包问题

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. 算法设计与分析第三章 动态规划-背包问题 杨圣洪

  2. 最化算法:动态规划基本步骤 • 找出最优解的性质,并刻划其结构特征。 • 递归定义最优值。有难度。 • 以自底向上的方式计算出最优值。非递归 • 根据计算最优值时得到的信息,构造最优解。! 第(1)为整体最优是否有局部最优。

  3. 3.10 0-1背包问题 • 给定n种物品和一背包。物品i的体积是wi,其价值为vi,背包的容量为C。问应如何选择装入背包的物品,使得装入背包中物品的总价值最大? • 0-1背包问题是一个 • 特殊的整数规划问题。 • (板右边表达式)

  4. 3.10 0-1背包问题--最优子结构 • 给定n种物品和一背包。物品i的体积是wi,其价值为vi,背包的容量为C。问应如何选择装入背包的物品,使得装入背包中物品的总价值最大? 若(y1,y2,…,yn)是全局最优解,则(y2,y3,…,yn)是子问题的最优解。 • 反证法假设子问题的最优解不是(y2,y3,…,yn),而是(z2,…,zn) 。 • 则z2v2+z3v3+…+znvn>y2v2+ y3v3 +…+ynvn, • 且z2w2 +…+znwnc-w1y1。 • 故w1y1+z2w2 +…+znwnc即(y1,z2,z3,…,zn)是原问题的可行解 • 但y1v1+ z2v2+z3v3+…+znvn> y1v1+ y2v2+ y3v3 +…+ynvn • 即(y1,z2,z3,…,zn)的价值高于(y1,y2,…,yn),这与(y1,y2,…,yn)是最优解矛盾!故假设错。

  5. 递归公式 • 将子问题最优值记为m(i,j),其中j为背包容量,i为候选物品的起始号,即候选物品为i,i+1,…,n。递归式如下: • 其中: (板递归公式) • m(i+1,j) 为不放物品i的最大价值 • m(i+1,j-wi)+vi 为放物品i.的最大值 • m(n,j) 从物品n开始逆序试装,直到m(1,C)

  6. 将子问题最优值记为m(i,j),j背包容量,i为候选物品的起始号。递归式如下: (活动区给出该公式,多算关键交互)

  7. 算法 void Knapsack(real* v,int* w,int c,int n,real** m){ //初始化数组m(n,j) for(int j=0;j<w[n] && j<=c;j++){m[n][j]=0;} for(int j=w[n];j<=c;j++){m[n][j]=v[n];} //已经最后一行m[n][j]的值,倒过计算m[i][j]的值 for (int i=n-1;i>1;i--){ //当容量j<w[i]时,物品i放不进,直接取同容量下行值 for(int j=0;j<w[i] &&j<=c;j++){m[i][j]=m[i+1][j];} //为j=w[i],+1,+2,..,c时价值 for(int j=w[i];j<=c;j++) { m[i][j]=max(m[i+1][j],m[i+1][j-w[i]]+v[i]);} } //以下i=1 if (c<w[1]) { //首行只要直接考虑容量j=c的情形,j<c均不考虑m[1][c]=m[2][c];} else { //如果包容量c>w[1]即物1能放入包中 m[1][c]=max(m[2][c],m[2][c-w[1]]+v[1]);}} //边讲边板算法 问题: 体积w[i] 不是整数 时如何办? 价值呢?

  8. 构造 当m(i,j)m(i+1,j)时,表示 m(i,j)=m(i+1,j-wi)+vi,表示 物品i被选中即xi=1,最后一列 下一个价值是m(i+1,j-wi) void Knapsack(real* v,int* w,int c,int n,real** m){ for(int j=0;j<w[n] && j<=c;j++){ m[n][j]=0;} for(int j=w[n];j<=c;j++){m[n][j]=v[n];} for (int i=n-1;i>1;i--){ for(int j=0;j<w[i] &&j<=c;j++){ m[i][j]=m[i+1][j];} for(int j=w[i];j<=c;j++) { m[i][j]=max(m[i+1][j], m[i+1][j-w[i]]+v[i]);} } //以下i=1 if (c<w[1]) { m[1][c]=m[2][c];} else { m[1][c]=max(m[2][c],m[2][c-w[1]]+v[1]); }} m[1][10]m[2][10] x[1]=1 j-wi=10-2=8 v=6 m[2][8]m[3][8] x[2]=1 j-wi=8-2=6,v=6+3=9 m[3][6]=m[4][6] x[3]=0 j=6 m[4][6]=m[5][6] x[4]=0 j=6 m[n][c]=m[5][6]>0 x[5]=1 j-wi=6-4=2,v=9+6

  9. 构造最优解算法描述 当m(i,j)m(i+1,j)时,表示 m(i,j)=m(i+1,j-wi)+vi,表示 物品i被选中即xi=1,最后一列 下一个价值是m(i+1,j-wi) void traceback(int**m,int* w,int c,int n,int *x){ for (int i=1;i<n;i++) { if (m[i][c]==m[i+1][c]) {x[i]=0;} else {x[i]=1;c=c-w[i];} } x[n]=(m[n][c]>0)?1:0; } m[1][10]m[2][10] x[1]=1剩余容量c=10-2=8 v=6 m[2][8]m[3][8] x[2]=1 剩余容量c=8-2=6,v=6+3=9 m[3][6]=m[4][6] x[3]=0 剩余容量c=6 m[4][6]=m[5][6] x[4]=0 剩余容量c=6 m[n][c]=m[5][6]>0 x[5]=1 剩余容量c=6-4=2,v=9+6

  10. 计算最优值算法及其复杂性 void Knapsack(real* v,int* w,int c,int n,real** m){ for(int j=0;j<w[n] && j<=c;j++) {m[n][j]=0;} for(int j=w[n];j<=c;j++){m[n][j]=v[n];} for (int i=n-1;i>1;i--){ for(int j=0;j<w[i] &&j<=c;j++){ m[i][j]=m[i+1][j];} for(int j=w[i];j<=c;j++) { m[i][j]=max(m[i+1][j], m[i+1][j-w[i]]+v[i]);} } //以下i=1 if (c<w[1]) { m[1][c]=m[2][c];} else { m[1][c]=max(m[2][c],m[2][c-w[1]]+v[1]); }} 数组m[n][c] 从m(i,j)的递归式及左边程序可知:计算时间为O(nc)。 当c很大时,计算时间较多。 例如c>2n时,需要Ω(n2n)。 能否优化呢?

  11. 关于m(i,j) • m(i,j)中很多值是重复的,重复计算浪费时间,只计算不重复的数据则节约时间 • 用p[i]记录第i的非重复值。点数据结构为(容量j,价值m(i,j)) • p[5]={(0,0),(4,6)} • p[4]={(0,0),(4,6),(9,10), (10,10) } • p[3]={(0,0),(4,6),(9,10),(10,11)} • p[2]={(0,0),(2,3),(4,6),(6,9),(9,10),(10,11)} • p[1]={(0,0),(2,6),(4,9),(6,12),(8,15)} • 如何递归算出p[i]呢?

  12. 快捷算法 • 由m(i,j)的计算公式可知,m(i,j)跳跃点集p[i] = • m(i+1,j)的跳跃点集p[i+1]  m(i+1,j-wi)+vi的跳跃点集q[i+1]。 • q[i+1]=p[i+1]各点加上(wi,vi) • 如何体现max(m(i+1,j), m(i+1,j-wi)+vi ) 对于p[i+1]q[i+1]中的2个点(a,b)和(c,d),若点(c,d)的ca且d<b即(c,d)体积大价值低,则应剔除。 • q[i+1]=p[i+1]各点加上(wi,vi), (板) • p[i] =p[i+1]  (q[i+1]-受控点) (板) • p[n+1]={(0,0)}, (板)

  13. 快捷算法(重点) • p[n+1]={(0,0)}, q[n+1] =p[n+1]+(wn,vn) p[n]=p[n+1]q[n+1]-低价点 q[n]=p[n]+(wn-1,vn-1)-超容点 p[n-1]=p[n]q[n]-低价点 …… q[i+1]=p[i+1]+(wi,vi)-超容点 p[i]=p[i]q[i]-低价点 …… q[2]=p[2]+(w1,v1)-超容点 p[1]=p[2]q[2]-低价点 p[6]={(0,0)} q[6]=p[6]+(4,6)={(4,6)} P[5]=p[6]+q[6]={(0,0),(4,6)} Q[5]=p[5]+(5,4)={(5,4),(9,10)} P[4]=p[5]+q[5]={0,0),(4,6),(5,4),(9,10)}-(5,4) ={(0,0),(4,6),(9,10)} Q[4]=p[4]+(6,5) ={(6,5),(10,11),(15,15)} ={(6,5),(10,11)} P[3]=p[4]+q[4]-(6,5) ={(0,0),(4,6),(9,10),(10,11)} Q[3]=p[3]+(2,3)={(2,3),(6,9)} P[2]=p[3]+q[3] ={(0,0),(2,3),(4,6),(6,9),(9,10),(10,11)} Q[2]=p[2]+(2,6) ={(2,6),(4,9),(6,12),(8,15)} P[1]=p[2]+q[2] ={(0,0),(2,6),(4,9),(6,12),(8,15)}

  14. 算法设计与实现 p[6]={(0,0)} , q[6]={(4,6)} p[5]={(0,0),(4,6)}, q[5]={(5,4),(9,10)} p[4]={(0,0),(4,6),(9,10)}, q[4]={(6,5),(10,11)} p[3]={(0,0),(4,6),(9,10),(10,11)}, q[3]={(2,3),(6,9)} p[2]={(0,0), (2,3),(4,6) , (6,9),(9,10),(10,11)} q[2]={(2,6),(4,9),(6,12),(8,15)} p[1]={(0,0),(2,6),(4,9),(6,12),(8,15)} P[i],q[i]的元素个数<=c p={ (0,0) , (0,0),(4,6), (0,0),(4,6),(9,10), (0,0),(4,6),(9,10),(10,11), (0,0), (2,3),(4,6) , (6,9),(9,10),(10,11) , (0,0),(2,6),(4,9),(6,12),(8,15)} q={ (4,6) , (5,4),(9,10), (6,5),(10,11), (2,3),(6,9) (2,6), (4,9),(6,12) , (8,15)} (难点) 各保存到一个数组中<=nc

  15. p={ (0,0) , (0,0),(4,6), (0,0),(4,6),(9,10), (0,0),(4,6),(9,10),(10,11), (0,0), (2,3),(4,6) , (6,9),(9,10),(10,11) , (0,0),(2,6),(4,9),(6,12),(8,15)} q={ (4,6) , (5,4),(9,10), (6,5),(10,11), (2,3),(6,9) (2,6), (4,9),(6,12) , (8,15)} 各保存到一个数组中<=nc p=new Array(n*c+1);//每个元素对应可能有c个不同的值,p[n+1]={(0,0)} (板) q=new Array(n*c+1);//值应该能保存 (板) hp=new Array(n+1);//物品i在p数组中的指针 (板) hq=new Array(n+1);//物品i在q数组中的指针 (板) for (i=0;i<n*c+1;i++){ p[i]=new Array(2);//每行二个元素,如(0,0) q[i]=new Array(2);//每行二个元素,如(5,4) } knapscak2(w,v,n,c);//体积数组,价值数组,物品个数,袋子的总体积

  16. q[i+1]=p[i+1](wi,vi), p[i]=p[i+1]q[i+1]-受控跳 //转抄p[i+1]到p[i] for (j=kp;j<=ip0;j++){ip=ip+1; p[ip][0]=p[j][0]; p[ip][1]=p[j][1];} //转抄q[i+1]-受控跳 for (j=iq0+1;j<=iq;j++){ t0=q[j][0];t1=q[j][1]; for (k=ip0;k<=ip;k++){ //受控点不进入 if ((t0>=p[k][0]) && (t1<p[k][1])) {break;} //替换原来差劲点 else if ( (p[k][0]>=t0) && (p[k][1]<t1) && (p[k][0]>0)) {p[k][0]=t0;p[k][1]=t1;break;}} if (k>ip){ //非受控则进入 ip=ip+1;p[ip][0]=t0;p[ip][1]=t1;} } //转抄q[i+1]-受控跳结束 hp[i]=ip; } //物品i处理完 } void knapscak2(w,v,n,c){ p[0][0]=0; p[0][1]=0; q[0][0]=0; q[0][1]=0; hp[n]=0; hq[n]=0; ip=0; iq=0; var ip0=1; var iq0=0; var kp=0; var kq=0; var t0=0; var t1=0; var i=0; var j=0; var k=0; for(i=n-1;i>=0;i--) { //q[i+1]=p[i+1]+(wi,vi), if (i==n-1) { kp=0;} else{kp=hp[i+2]+1;} iq0=iq; //kp上个起始位=上上尾+1 for (j=kp;j<=hp[i+1];j++){ t0=p[j][0]+w[i];t1=p[j][1]+v[i]; if (t0<=c) { iq=iq+1;q[iq][0]=t0;q[iq][1]=t1;} } hq[i]=iq; ip0=ip;//当前值

  17. q[i+1]={(j+wi,m(i,j)+vi}构造解 var imax=hq[1]+1//倒数第2轮的结束处+1为最后一轮起始点 for (i=hq[1]+1;i<=hq[0];i++) {imax=(q[i][1]>q[imax][1])?i:imax;} //以此最大值为基准不断倒查, var x=new Array(n); for (i=0;i<n;i++) {x[i]=0;} var t0=q[imax][0]; //8 var t1=q[imax][1]; //15 var mf=0; for(i=0;i<n;i++){ mf=0; for(j=n-1;j>=i;j--){ for (k=hq[j+1]+1;k<=hq[j];k++) { if ( (q[k][0]==t0) && (q[k][1]==t1) ) { x[j]=1;t0=t0-w[j]; t1=t1-v[j];mf=1;break; }} if (mf==1){ break; } }} q={ (4,6), (5,4),(9,10), (6,5),(10,11), (2,3),(6,9) (2,6), (4,9),(6,12) , (8,15)}

  18. 算法复杂度分析 • 算法描述:P80-81 • 主要计算量在于计算跳跃点集p[i](1≤i≤n)。 • 由于q[i+1]=p[i+1](wi,vi),算q[i+1]要O(|p[i+1]|)。 • p[i]=p[i+1]q[i+1]-受控跳跃点,O(|p[i+1]|)计算时间。 • 从p[i]的定义可以看出,p[i]中的跳跃点相应于xi,…,xn的0/1赋值,其实真值表可能组合。因此p[i]中跳跃点个数不超过2n-i+1,等比数例的和(qn-q0)/(q-1)=O(qn)。 • 由此可见,算法计算跳跃点集p[i]所花费的计算时间为 • 改进后算法的计算时间复杂性为O(2n)。 • 当所给物品的重量wi(1≤i≤n)是整数时,|p[i]|≤c+1,(1≤i≤n)。改进后计算时间复杂性为O(min{nc,2n})。

More Related