5-32 子集树问题
问题描述
试设计一个用回溯法搜索子集空间树的函数。该函数的参数包括结点可行性判定函数和上界函数等必要的函数,并将此函数用于解装载问题。
装载问题描述如下:有一批共 n 个集装箱要装上艘载重量为 c 的轮船,其中集装箱 i 的重量为 wi 。找出一种最优装载方案,将轮船尽可能装满,即在装载体积不受限制的情况下,将尽可能重的集装箱装上轮船。
第一行有 2 个正整数 n 和 c。n 是集装箱数,c 是轮船的 载重量。接下来的 1 行中有 n 个正整数,表示集装箱的重量。
Java
package Chapter5HuiSuFa;
import java.util.Scanner;
public class ZiJiShu {
private static int n,c;
private static int[] x,bestx,w;
private static int r,cw,bestw;
public static void main(String[] args){
Scanner input = new Scanner(System.in);
while (true){
bestw = 0;
cw = 0;
r = 0;
n = input.nextInt();
c = input.nextInt();
w = new int[n+1];
x = new int[n+1];
bestx = new int[n+1];
for(int i=1; i<=n; i++)
w[i] = input.nextInt();
for(int i=1; i<=n; i++)
r += w[i];
backtrack(1);
output();
}
}
private static void backtrack(int t){
if(t > n) record();
else
for(int i=0; i<=1; i++){
x[t] = i;
if(constraint(t) && bound(t)){
change(t);
backtrack(t+1);
restore(t);
}
}
}
private static void record(){
if(cw > bestw){
bestw = cw;
for(int i=1; i<=n; i++)
bestx[i] = x[i];
}
}
private static boolean constraint(int t){
if(x[t]==0 || x[t]==1 && cw+w[t]<=c) return true;
else return false;
}
private static boolean bound(int t){
if(x[t]==1 || x[t]==0 && cw+r-w[t]>bestw) return true;
else return false;
}
private static void change(int t){
if(x[t] == 1) cw+=w[t];
r -= w[t];
}
private static void restore(int t){
if(x[t] == 1) cw-=w[t];
r += w[t];
}
private static void output(){
System.out.println(bestw);
for(int i=1; i<=n; i++)
System.out.print(bestx[i]+" ");
}
}
Input & Output
5 10
7 2 6 5 4
10
0 0 1 0 1
30 566
93 60 57 47 7 88 41 60 95 6 82 20 28 79 20 53 69 71 44 96 64 68 23 27 13 45 68 66 69 99
566
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 0 1 0 1 1 1 1
Reference
王晓东《计算机算法设计与分析》(第3版)P187