构造增量法生成子集

题意:

生成 1~n 集合的子集, 先按元素从小到大再按字典序排列输出

分析:

所谓构造增量法, 就是每次都输出当前数组的元素, 然后再给当前数组最大元素一个增量, 看是否仍然在集合内, 如果在就把他继续放进数组, 输出。 这种方法不需要显式确认递归边界, 如果无法添加元素, 自然就不会再递归了。 数据结构我选用了string , 因为字典序比较容易排序出来。

#include <bits/stdc++.h>
using namespace std;
string ans[1 << 15  + 5];
int A[10];
int cnt = 0;
void print_subset(int n, int* A, int cur){
    for(int i = 0; i < cur; i++)
    {
       ans[cnt] += A[i] + ‘0‘;
    }
    cnt++;
    int s = cur ? A[cur-1] + 1 : 1;// 确定已选元素的最大可能值
    for(int i = s; i <= n; i++){
        A[cur] = i;
        print_subset(n, A, cur + 1); // 递归构造子集
    }
}
bool cmp(string a, string b){
    if(a.size() < b.size())
        return true;
    else if(a.size() == b.size()){
        return a < b;
    }
    else return false;
}
int main() {
  int n;
  while(scanf("%d", &n) != EOF){
      cnt = 0;
      print_subset(n, A, 0);
      sort(ans, ans + cnt, cmp);
      cout << 0 <<endl;
      for(int i = 1; i < cnt; i++){
         cout << ans[i].size() <<" " << ans[i][0] - ‘0‘;
         for(int j = 1; j < ans[i].size(); j++){
            cout <<" " << ans[i][j] - ‘0‘;
         }
         ans[i] = "";
         cout << "\n";
      }
      printf("\n");
  }
  return 0;
}
时间: 2024-10-07 05:28:26

构造增量法生成子集的相关文章

ACM:回溯法,子集生成

(一)增量构造法 #include <iostream> #include <algorithm> using namespace std; const int MAXN = 1000; int A[MAXN], n; void print_subset(int n, int *A, int cur) { for(int i = 0; i < cur; ++i) cout << A[i] << " "; cout <<

(算法初步学习)蛮力法解决生成子集问题

关于蛮力法求生成子集问题 对于算法分析中的问题我已经不想对自己说什么了,到了大三了,竟然还是小白.对生成子集问题我研究了一下午,最后终于想通了.思路:   1.利用<math.h> 头文件中的pow(x,y)函数来求得2的n次方,作为外循环.2.然后写一个将10进制数转换为2进制数的函数(当然,C中有专门的转换进制的函数在<stdlib.h>中,但是,他转换下来  5不是0101而是101,这就导致需要分开判断,所以不用itoa函数).如下:conversation(int n,i

生成子集

1 生成子集 1.1 含义 给定一个集合,枚举它所有可能的子集. 比如给定集合{1,2,3},应该输出: {} {1} {2} {1, 2} {3} {1, 3} {2, 3} {1, 2, 3} 1.2 增量构造法 增量构造法,每次选择一个元素放到集合中,每次操作的结果即是一个子集. 递归操作,每次向当前集合中添加一个比当前集合中最大的元素大1的数. 代码: from __future__ import print_function def print_subset(n, lst, cur):

【BZOJ-1336&amp;1337】Alie最小圆覆盖 最小圆覆盖(随机增量法)

1336: [Balkan2002]Alien最小圆覆盖 Time Limit: 1 Sec  Memory Limit: 162 MBSec  Special JudgeSubmit: 1573  Solved: 697[Submit][Status][Discuss] Description 给出N个点,让你画一个最小的包含所有点的圆. Input 先给出点的个数N,2<=N<=100000,再给出坐标Xi,Yi.(-10000.0<=xi,yi<=10000.0) Outpu

阅读《构造之法》1、2、3章有感

<构造之法>和其他接触过的教材有所区别,不像别的教材那样呆板,无趣,让人读着想睡觉,感觉像是在听笔者在讲述他的所见所闻,或者像在读一本小说,让人可以一直跟着读下去,而且能学到一些东西. 在第一章中,有许多生动有趣的例子(事实整本书都有许多),让我能很有兴趣的慢慢读下来,也比较明白了软件工程什么,它所包含的方面以及意义,软件工程与许多的学科都有联系,这些联系或多或少,也说明了软件工程不单单只是涉及到一方面.软件工程的目标也比较明确,看这些可以解决自己对这一专业的迷惑.第二章则深入一些的讲到了对于

BZOJ 2280 Poi2011 Plot 二分答案+随机增量法

题目大意:给定n个点,要求分成m段,使每段最小覆盖圆半径的最大值最小 二分答案,然后验证的时候把点一个个塞进最小覆盖圆中,若半径超了就分成一块-- 等等你在跟我说不随机化的随机增量法? 好吧 那么对于一个点pos,我们要计算最大的bound满足[pos,bound]区间内的最小覆盖圆半径不超过二分的值 直接上二分是不可取的,因为我们要求m次,如果每次都验证一遍[1,n/2]直接就炸了 我们可以这么搞 首先判断[pos,pos+1-1]是否满足要求 然后判断[pos,pos+2-1]是否满足要求

Reaction to 构造之法 of Software Engineering From The First Chapter toThe Fifth Chapter(补充版)

几个星期前,我阅读过一篇文章,一位老师教导自己的学生要积极地去阅读文学文献,其中,我很欣赏他的一句话:“Just think of liturature as if you're reading a long text-message”.引申到这里,对比后才发现自己在现实生活中真的很少在课后花时间来细看自己的专业书籍,说来惭愧,这种情况出现的频率最多的就是在学期末备战考试了.因为这次的作业,我似乎告诉自己这是一个非常“恰当”的理由去让自己提前去完成未完的“任务”.阅读一本书,就要认真,要对得起自

现代软件构造之法

现代软件工程方法之所以超出传统方法,主要是因为它针对的是具体对象,即面向的是具体存在的问题和弊端,这一点,完全克服了传统软件工程方法的缺点和不足.现代软件工程方法包含五部分,分别是分析.设计.编码.测试.维护.这几部分虽与传统工程方法大同小异,但细比较便可发现现代工程方法的优点.在分析部分,传统工程方法主要是笼统地分析,没有具体的面向对象,而现代工程方法则是分析现实事件的具体问题,因此,具体问题的性质可以更好地反映事件的性质.在设计部分,面向对象主要是系统中的具体时间.构造之法的主要作用--提高

BZOJ 1337 最小圆覆盖 随机增量法

题意:链接 方法:随机增量法 解析: 首先把所有点打乱. 然后枚举第一个点,如果不在当前的圆内则把它设为圆心. 再枚举第二个点,如果不在当前的圆内则把圆设为其与第一个点的距离为直径的圆. 再枚举第三个点,如果不在当前的圆内则把圆设为这三个点构成三角形的外接圆. 然后最后就是答案了. 别问我这为什么是对的- -! 复杂度期望O(n),我是信了. 代码: #include <cmath> #include <cstdio> #include <iomanip> #inclu