[問題描述]
已知n個正數:wi, 1<=i<=n, 和M。要求找出{wi }的所有子集使得子集內元素之和等於M。例如:
n=4, (w1,w2,w3,w4)=(11,13,24,7),M=31
則滿足要求的子集是(11,13,7)和(24,7)。
/*子集和數問題:已知n個正數:wi, 1<=i<=n, 和M。
要求找出{wi }的所有子集使得子集內元素之和等於M。例如:
n=4, (w1,w2,w3,w4)=(11,13,24,7),M=31
則滿足要求的子集是(11,13,7)和(24,7)。
思路:
子集和數問題解的一種表示方法
解由n-元組(x1, x2, …, xn)表示;
顯式約束條件xi∈{0,1} ,1≤i≤n,如果沒有選擇Wi,則xi=0;
如果選擇了Wi,則xi=1。於是上面的解可以表示為(1,1,0,1)和(0,0,1,1);
隱式約束條件(xi× wi)的和數為M
*/
public class sonNum {
//定義一個數組表示集合
static int[] num = {11,13,24,7};
//sum用來做加法,比較判斷是否等於m
static int sum = 0;
//用來表示最終的解{0,1,1,1}形式
static int[] result = new int[num.length];
//給定的m
static int m = 31;
//回溯方法
static public void backTrack(int count){
//如果count等於集合的長度則代表已經運行結束
if(count == result.length){
return;
}
else{
//1的情況代表選擇將該數加進sum里,0的情況就是不要這個數
for (int i = 0; i <= 1 ; i++) {
sum += i*num[count];
//result用來記錄是否選擇該數 選擇則置1,不選擇則置0
result[count] = i ;
//如果運行到sum等於m的時候,則代表找到了一組解
//將這組解打印輸出
if(sum == m){
for (int j = 0; j < result.length; j++) {
//判斷當前數的狀態是否為選中狀態 是則將該數打印出來
if(result[j] == 1){
System.out.print(num[j]+"\t");
}
}
System.out.println();
}
//如果當前sum小於m,則進行下一個數的判斷
if(sum < m){
backTrack(count+1);
}
//回溯
sum -= i*num[count];
}
}
}
public static void main(String[] args) {
backTrack(0);
}
}
