1. 程式人生 > >【子集或者DFS】部分和問題

【子集或者DFS】部分和問題

pub image 生成 add 所有 while 元素 檢查 get

題目:

  給定整數序列a1,a2,...,an,判斷是否可以從中選出若幹數,使它們的和恰好為k。1≤n≤20 -108≤ai≤108 -108≤k≤108
  輸入:

n=4
a={1,2,4,7}
k=13

  輸出:

Yes (13 = 2 + 4 + 7)

思路:

  這裏記錄一下為什麽會想到用子集去做這道題目,這道題目是關於從幾個數中找出幾個關於符合某種關系的數,吶,根據模式匹配法很容易想到這種方法,而關於這種方法也可以推廣開來,也就是說只要在n個數據中找幾個數據都可以用求子集的方式去做。

代碼:

 1 import
java.util.ArrayList; 2 import java.util.Arrays; 3 import java.util.Scanner; 4 5 public class 部分和 { 6 7 private static int kk; 8 9 public static void main(String[] args) { 10 Scanner sc = new Scanner(System.in); 11 int n = sc.nextInt(); 12 int
[] A = new int[n]; 13 for (int i = 0; i < n; i++) { 14 A[i] = sc.nextInt(); 15 } 16 int k = sc.nextInt();//13 17 18 System.out.println("================解法一============="); 19 ArrayList<ArrayList<Integer>> subsets = getSubsets(A, A.length);
20 int count = 0; 21 for (int i = 0; i < subsets.size(); i++) { 22 for (int j = 0; j < subsets.get(i).size(); j++) { 23 count += subsets.get(i).get(j); 24 25 if (count==k&&j==subsets.get(i).size()-1) { 26 System.out.println("yes k = "+subsets.get(i)); 27 } 28 } 29 count = 0; // 如果沒找到 要將count置為0 30 } 31 // System.out.println(subsets); 32 33 System.out.println("================解法二============="); 34 kk = k; 35 dfs(A, k, 0, new ArrayList<Integer>()); 36 } 37 /** 38 * 本題最優解法 二進制求取所有子集然後求和等於k解決問題 39 */ 40 public static ArrayList<ArrayList<Integer>> getSubsets(int []A,int n){ 41 Arrays.sort(A); // 正序排序 42 ArrayList<ArrayList<Integer>> res = new ArrayList<>(); //大集合 43 for(int i = ex(2, n);i>0;i--){ //大數字-1 44 ArrayList<Integer> s = new ArrayList<>(); //對每個i建立一個集合 45 for(int j = n-1;j>=0;j--){ //檢查哪個位上的二進制為1,從高位開始檢查,高位對應著數組靠後的元素 46 if(((i>>j)&1)==1){ 47 s.add(A[j]); 48 } 49 } 50 res.add(s); 51 } 52 // 生成的結果逆序排序,如果要生成正序排列,很難完成,只有數組反轉實現。 53 return res; 54 } 55 56 public static int ex(int a,int n){ 57 if(n==0)return 1; 58 if(n==1)return a; 59 int temp = a; // a的1次方 60 int res = 1; 61 int exponent = 1; 62 while((exponent<<1)<n){ 63 temp = temp * temp; 64 exponent = exponent << 1; 65 } 66 res *= ex(a,n-exponent); 67 return res * temp; 68 } 69 70 private static void dfs(int[] a, int k, int cur, ArrayList<Integer> ints) { 71 if (k == 0) { 72 System.out.print("Yes (" + kk + " = "); 73 int size = ints.size(); 74 for (int i = 0; i < size; i++) { 75 System.out.print(ints.get(i) + (i == size - 1 ? "" : " + ")); 76 } 77 System.out.println(")"); 78 System.exit(0); 79 } 80 if (k < 0 || cur == a.length) 81 return; 82 83 dfs(a, k, cur + 1, ints);// 不要cur這個元素 84 85 ints.add(a[cur]); 86 int index = ints.size() - 1; 87 dfs(a, k - a[cur], cur + 1, ints); 88 ints.remove(index);// 回溯 89 } 90 }

結果:

  技術分享圖片

【子集或者DFS】部分和問題