設集合S={x1,x2,…,xn}是一個正整數集合,c是一個正整數,子集和問題判定是否存在S的一個子集S1,使S1中的元素之和為c。試設計一個解子集和問題的回溯法。
輸入格式:
輸入數據第1行有2個正整數n和c,n表示S的大小,c是子集和的目標值。接下來的1行中,有n個正整數,表示集合S中的元素。 是子集和的目標值。接下來的1 行中,有n個正整數,表示集合S中的元素。
輸出格式:
輸出子集和問題的解,以空格分隔,最后一個輸出的后面有空格。當問題無解時,輸出“No Solution!”。
輸入樣例:
在這里給出一組輸入。例如:
5 10
2 2 6 5 4
輸出樣例:
在這里給出相應的輸出。例如:
2 2 6
本題要求只輸出第一個解,並采用回溯法,所以可以主體來枚舉所有情況,然后再剪枝剪掉不需要的分支:
package 宿題;
import java.io.*;
public class PTASubsetSum {
static int c;
static int n;
static boolean Out=true;//這里新建一個標記位,用來記錄有無第一個解出現,結束遞歸;
public static void main(String args[])throws IOException{
StreamTokenizer in=new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));//當需要輸入大量數據時BufferedReader處理速度快,比Scanner高效;
in.nextToken();
n=(int)in.nval;
in.nextToken();
c=(int)in.nval;
int a[]=new int[n];
int SUM=0;
for(int i=0;i<n;i++){
in.nextToken();
a[i]=(int)in.nval;
SUM+=a[i];//減去當所有數和小於c時的分支;
}
if(SUM>=c){
Count(a,0,0,"");
if(Out)
System.out.println("No Solution!");
}else
System.out.println("No Solution!");
}
private static void Count(int a[],int count,int sum,String s){
if(count<n&&Out){
if(sum+a[count]==c){
Out=false;//結束遞歸;
System.out.println(s+a[count]+" ");
}else if(sum+a[count]<c){//分支向下求解;
Count(a,count+1,sum+a[count],s+a[count]+" ");
System.out.println(s+a[count]+" ");
}
Count(a,count+1,sum,s);
System.out.println(s);
}
}
}
該算法最壞情形下時間復雜度為O(2^n)。