概述
有一批共n个集装箱要装上2艘载重量分别为c1,c2的轮船,其中集装箱i的重量为wi,且要求确定是否有一个合理的装载方案可将这n个集装箱装上这2艘轮船。可证明,采用如下策略可以得到一个最优装载方案:先尽可能的将第一艘船装满,其次将剩余的集装箱装到第二艘船上。
解题思路
- 首先将第一艘轮船尽可能装满。
- 将剩余的集装箱装上第二艘轮船。
在算法的while
循环中,首先检测当前扩展结点的左儿子结点是否为可行结点。如果是则将其加入到活结点队列中。然后将其右儿子结点加入到活结点队列中(右儿子结点一定是可行结点)。2个儿子结点都产生后,当前扩展结点被舍弃。
活结点队列中的队首元素被取出作为当前扩展结点,由于队列中每一层结点之后都有一个尾部标记-1,故在取队首元素时,活结点队列一定不空。当取出的元素是-1时,再判断当前队列是否为空。如果队列非空,则将尾部标记-1加入活结点队列,算法开始处理下一层的活结点。
节点的左子树表示将此集装箱装上船,右子树表示不将此集装箱装上船。设bestw
是当前最优解;ew
是当前扩展结点所相应的重量;r
是剩余集装箱的重量。则当ew+r<bestw
时,可将其右子树剪去,因为此时若要船装最多集装箱,就应该把此箱装上船。另外,为了确保右子树成功剪枝,应该在算法每一次进入左子树的时候更新bestw
的值。
为了在算法结束后能方便地构造出与最优值相应的最优解,算法必须存储相应子集树中从活结点到根结点的路径。为此目的,可在每个结点处设置指向其父结点的指针,并设置左、右儿子标志。
找到最优值后,可以根据parent
回溯到根节点,找到最优解。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| 变量含义: Ew: 扩展节点的载重量 W: 重量数组 Q: 活节点队列 bestw: 当前最优载重量 i: 当前处理到的层数 n: 总货物数
while (true) { if (Ew + w[i] <= c) EnQueue(Q, Ew + w[i], bestw, i, n); EnQueue(Q, Ew, bestw, i, n); Q.Delete(Ew);
if (Ew == -1) { if (Q.IsEmpty()) return bestw; Q.Add(-1); Q.Delete(Ew); i++; } }
|
程序代码
备注:C++和Java版本并没有实现最优解。
C++代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
| #include<iostream> #include<queue> using namespace std;
void enqueue(queue<int> &Q,int wt,int &bestw,int i,int n) { if(i==n) { if(wt>bestw) bestw=wt; }else Q.push(wt); }
int MaxLoading(int w[],int c,int n) { queue<int> q; q.push(-1); int i=1; int EW=0,bestw=0; while(true) { if(w[i]+EW<=c) { enqueue(q,w[i]+EW,bestw,i,n); } enqueue(q,EW,bestw,i,n); EW=q.front(); q.pop(); if(EW==-1) { if(q.empty()) return bestw; q.push(-1); EW=q.front(); q.pop(); i++; } } } void main() { int n=3; int c =50; int w[100]={10,40,50};
int bestw = MaxLoading(w,c,n); cout<<"做大装载量为"<<bestw<<endl; cout<<"end"; }
|
Java代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182
| package demo1;
public class BranchLimitFIFOSearch {
public static void main(String[] args) { int n = 3; float c1 = 50; float c2 = 50; float[] w = { 0, 10, 40, 40 };
BranchLimitFIFOSearch bfis = new BranchLimitFIFOSearch(n, c1, c2, w); float s = bfis.getS(); if (s <= c1 || s <= c2) { System.out.println("只需要1首船!"); } if (s > c1 + c2) { System.out.println("2首船不能解决问题!"); return; } bfis.maxLoading(c1); float bestw = bfis.getBestw();
if (s - bestw <= c2) { System.out.println("第1首船装载: " + bestw); System.out.println("第2首船装载: " + (s - bestw)); } else { System.out.println("不能解决问题"); }
}
private int n; private float c1; private float c2; private float bestw; private float ew = 0; private float[] w; private float s = 0; private MyQueue mq = new MyQueue();
public BranchLimitFIFOSearch(int _n, float _c1, float _c2, float[] _w) { n = _n; c1 = _c1; c2 = _c2; w = _w; for (float f : _w) { s += f; } }
public float maxLoading(float c) { mq.put(new Float(-1)); int i = 1; ew = 0; bestw = 0; while (!mq.empty()) { if (ew + w[i] <= c) { addLiveNode(ew + w[i], i); } addLiveNode(ew, i); ew = (Float) mq.get(); if (ew == -1) { if (mq.empty()) { return bestw; } mq.put(new Float(-1)); ew = (Float) mq.get(); i++; } } return bestw; }
public void addLiveNode(float wt, int i) { if (i == n) { if (wt > bestw) { bestw = wt; } } else { mq.put(new Float(wt)); } }
public int getN() { return n; }
public void setN(int n) { this.n = n; }
public float getC1() { return c1; }
public void setC1(float c1) { this.c1 = c1; }
public float getC2() { return c2; }
public void setC2(float c2) { this.c2 = c2; }
public float getBestw() { return bestw; }
public void setBestw(float bestw) { this.bestw = bestw; }
public float getEw() { return ew; }
public void setEw(float ew) { this.ew = ew; }
public float getS() { return s; }
public void setS(float s) { this.s = s; }
}
|
活动队列
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| package demo1;
import java.util.LinkedList;
public class MyQueue { private LinkedList ll = new LinkedList();
public void put(Object o) { ll.addLast(o); }
public Object get() { return ll.removeFirst(); }
public boolean empty() { return ll.isEmpty(); } }
|