求子集问题

从订阅博客中看到这道题,于是花了上午的时间写了一下,此题类似于0-1背包问题,故复习了一下,分别有递归和非递归的解法。

题目:给定一个数t,以及n个整数,在这n个整数中找到相加之和为t的所有组合,例如t = 4n = 6,这6个数为[4, 3, 2, 2, 1, 1],这样输出就有4个不同的组合,它们的相加之和为44, 3+1, 2+2, and 2+1+1。请设计一个高效算法实现这个需求。

递归解法:

    private static int[] a={4,3,2,2,2,1,1};

    private static int t=8;

    private static int n=7;

    private static boolean[] flags;

   

    public static int subNum(int s,int r){

        if(s==0){

            output(0);

            // System.out.println(r);

            return 1;

        }else{

            if(s<0 || (s>0 && r>=n)){

                return 0;

            }else{

                flags[r]=true;

                int f=subNum(s-a[r],r+1);

// while (r+1<n && a[r+1] == a[r])

// r++;

                flags[r]=false;

                f=subNum(s,r+1);

                return 0;

                /*

                 * if(subNum(s-a[r],r+1)==1){ //System.out.println(s+" "+r);

                 * return 1; }else{ flags[r]=false; return subNum(s,r+1); }

                 */

            }

        }

    }

 

非递归算法:

private final static int N = 20;

 private static int W[] = { 1, 1, 1, 2, 2, 3, 4, 4, 5, 5, 5, 8, 8, 8, 10,
   10, 10, 12, 12, 12 };

 // private static int W[]={4,3,2,2,2,1,1}; // 若原W无序,则先对其排序
 private final static int T = 20;

 private static int stack[] = new int[20];

 private static int stackIdx;

 private static void output() {
  int i;
  for (i = 0; i < stackIdx; i++) {
   System.out.print(W[stack[i]] + " ");
  }
  System.out.println();
 }

 private static void outstack() {
  int i;
  for (i = 0; i < stackIdx; i++) {
   System.out.print(stack[i] + " ");
  }
  System.out.println();
 }

 public static void subNum() {
  int idx;
  int sum;
  idx = 0;
  sum = T;
  stackIdx = 0;
  while (stackIdx >= 0) {
   // System.out.println(" "+stackIdx+ " "+sum+" "+idx);
   if (idx >= N) {
    --stackIdx;
    if (stackIdx < 0)
     break;
    sum += W[stack[stackIdx]];
    idx = stack[stackIdx];
    while (idx + 1 < N && W[idx + 1] == W[idx])
     idx++;//
前后的元素相同,即可以跳过后面相同的元素,因为已经在前面一个元素遍历过

    ++idx;
   } else {
    sum -= W[idx];
    stack[stackIdx++] = idx;
    // System.out.println(" "+stackIdx+ " "+sum+" "+idx);
    if (sum == 0) {
     output();
     --stackIdx;
     sum += W[idx];
     while (idx + 1 < N && W[idx + 1] == W[idx])
      idx++;//
找到符合的条件,而下一次遍历的元素跟符合条件中的最后一个元素相同,即表明有重复相同的组合
     ++idx;
    } else if (sum > 0) {
     ++idx;
    } else {
     --stackIdx;
     if (stackIdx < 0)
      break;
     sum += W[idx];
     idx = stack[stackIdx] + 1;
     // while(idx+1<N && W[idx+1] == W[idx]&& flag)
     // idx++;
    }
   }
  }

 }

 

1、数字三角形问题 步骤: 1.读入数字三角形的行数n和具体数字三角形。 2.从第n-1行开始向上逐行计算,对于每个数字,将其与下面一行相邻的两个数比较取最大值,然后加上该数字,更新该位置的数值。 3.最终得到的数字三角形的顶部数字即为所的最大值。 示例代码: ```python n = int(input()) #读入行数 triangle = [] for i in range(n): row = list(map(int, input().split())) triangle.append(row) for i in range(n-2, -1, -1): # 从倒数第二行开始向上逐行计算 for j in range(i+1): triangle[i][j] += max(triangle[i+1][j], triangle[i+1][j+1]) print(triangle[0][0]) #输出最大值 ``` 2、子集问题 步骤: 1.读入正整数集合X和目标和y。 2.定义一个回溯函数backtrack,它的参数是当前考虑到的元素下标i和已选中的元素之和sum。 3.在回溯函数中,当sum等于目标和y时,将已选中的元素加入结果集合res。当i等于n时,返回。 4.对于当前考虑的元素xi,有选或不选两种可能性。如果选,将xi加入已选中的元素集合,并将i+1作为新的参数递归调用backtrack。如果不选,直接将i+1作为新的参数递归调用backtrack。 示例代码: ```python n, y = map(int, input().split()) #读入集合X和目标和y X = list(map(int, input().split())) res = [] def backtrack(i, sum, path): if sum == y: res.append(path[:]) return if i == n: return #选当前元素 path.append(X[i]) backtrack(i+1, sum+X[i], path) path.pop() #不选当前元素 backtrack(i+1, sum, path) backtrack(0, 0, []) print(res) #输出符合条件的子集 ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值