【子集或者DFS】部分和问题

题目:

  给定整数序列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 }

结果:

  

猜你喜欢

转载自www.cnblogs.com/xiaoyh/p/10346658.html