[Aizu] ITP2_11_A~D: 子集的枚举系列

前言

ITP系列之使用位集枚举, 具体内容参见bitset
PS: 感觉第三个与第四个拓展之后实用性较强

题目链接

ITP2_11_A: Enumeration of Subsets I
ITP2_11_B: Enumeration of Subsets II
ITP2_11_C: Enumeration of Subsets III
ITP2_11_D: Enumeration of Combinations

求解

第一题

分析

要求n个数的组合, 组合内元素数量不限, 创建一个位集, 从0一直增加到小于2的n次方即可, 每次都输出

代码

#include <bits/stdc++.h>
using namespace std;

void print(bitset<20> b) {
    for (int i = 0; i < 20; i++) {
        if (b.test(i)) {
            cout << " " << i;
        }
    }
}

int main(void) {
    ios::sync_with_stdio(false);
    cin.tie(0);

    bitset<20> b1, b2;
    int n;

    cin >> n;
    int max = 1 << n;
    for (int i = 0; i < max; i++) {
        cout << i << ":";
        b2 = i;
        print(b2);
        cout << endl;
    }
}

第二题

分析

求n个数的组合, 组合满足T集合是它的子集, 如T = {1, 2}, 那么形如{1, 2, 3}, {1, 2, 5}等这种都可以, {2, 3, 5} 这种不可以

代码

#include <bits/stdc++.h>
using namespace std;

void print(bitset<20> b) {
    for (int i = 0; i < 20; i++) {
        if (b.test(i)) {
            cout << " " << i;
        }
    }
}

int main(void) {
    ios::sync_with_stdio(false);
    cin.tie(0);

    bitset<20> b1, b2;

    int n; cin >> n;
    int max = 1 << n;
    int k; cin >> k;
    for (int i = 0; i < k; i++) {
        int x; cin >> x;
        b1.set(x);
    }
    for (int i = 0; i < max; i++) {
        b2 = i;
        if ((b2 | b1) == b2) {
            cout << i << ":";
            print(b2);
            cout << endl;
        }
    }
}

第三题

分析

给定一个集合T, 是S集合的子集, S集合是一个简单的集合 0 ~ n-1, 而T集合则是其中特定的元素的集合, 要求输出所有集合T的元素的全组合
通过用一个位集一点点增加上去, 会发生超时.
如果把T看作一个数组, 那么就可以使用一个长度为T的长度的位集, 来依次增加, 得到的一个位集作为T中元素的下标, 然后输出即可

代码

#include <bits/stdc++.h>
using namespace std;

void print(bitset<32> b) {
    for (int i = 0; i < 32; i++) {
        if (b.test(i)) {
            cout << " " << i;
        }
    }
}

int main(void) {
    ios::sync_with_stdio(false);
    cin.tie(0);

    bitset<32> b1, b2;
    vector<int> vec;

    int n; cin >> n;
    int k; cin >> k;
    int max = 1 << k;
    for (int i = 0; i < k; i++) {
        int x; cin >> x;
        vec.push_back(x);
    }
    for (int i = 0; i < max; i++) {
        b1 = i;
        b2.reset();
        for (int j = 0; j < vec.size(); j++) {
            if (b1.test(j) == 1) {
                b2.set(vec[j]);
            }
        }
        cout << b2.to_ulong() << ":";
        print(b2);
        cout << endl;
    }
}

第四题

分析

要求的是从n个数中取出k个数的全组合, n个数分别为 0 ~ n-1, 创建一个位集, 然后从值从0一直增加, 如果1的数量恰好为k个, 输出即可

代码

#include <bits/stdc++.h>
using namespace std;

int main(void) {
    ios::sync_with_stdio(false);
    cin.tie(0);

    int n, k; cin >> n >> k;
    bitset<18> b;
    int max = 1 << n;
    for (int i = 0; i < max; i++) {
        b = i;
        if (b.count() == k) {
            cout << i << ":";
            for (int j = 0; j < n; j++) {
                if (b.test(j))
                    cout << " " << j;
            }
            cout << endl;
        }
    }
}

原文地址:https://www.cnblogs.com/by-sknight/p/11026392.html

时间: 2024-10-12 13:46:28

[Aizu] ITP2_11_A~D: 子集的枚举系列的相关文章

poj 1270 Following Orders 枚举排列

题意: 给一个字符集和一些字符之间的小于关系,求字符集上的所有可能排列. 分析: 暴力枚举可以分为枚举子集,枚举排列,枚举组合,这题是个简单的枚举排列,枚举过程中用小于关系剪枝即可. 代码: //poj 1270 //sep9 #include <iostream> #include <algorithm> using namespace std; char vars[64],constraint[256],ans[64]; int g[128][128],vis[256]; in

UVa1354 Mobile Computing (枚举二叉树)

链接:http://acm.hust.edu.cn/vjudge/problem/41537分析:二进制法枚举二叉树.用n位二进制位代表n个元素,第i位为1代表集合中包含第i个元素,否则不包含.从右往左依次表示第0,1,2,3...n-1号元素,sum表示包含集合中的元素时的总重量,tree[subset]表示包含集合中的元素时天平合法的L和R,vis表示当前子集是否已经被枚举过避免重复枚举.然后就是dfs递归枚举子集,枚举左子树的集合剩下的就是右子树,然后继续递归枚举,枚举到叶子结点或vis为

1354 Mobile Computing(暴力、二进制枚举、简直无情)

翘了3节课来A这道题,最后还超时了,也是蛮拼的.. 没做出来主要一个方面就是不会一个二进制数子集的枚举 这里上一下代码: for(int S0 = S; S0; S0 = (S0 - 1) & S){ } 这里S0就是S的子集了~! 题目的思路就是枚举所有情况,注意记忆化[话说这题学到了不少] #include<cstdio> #include<cstring> #include<vector> #include<algorithm> using n

枚举非空真子集

第一种情况给定的集合是满状态的,也就是枚举2的n次方种状态下的每一种子集的情况. for(int x=0;x<(1<<n);x++) 这里的x是一个二进制数,其长度为n,取值为00000...00000~11111...11111的每一种状态. for(int i=0;i<n;i++) if(x&(1<<i)) 这里的i的取值为1,10,100,1000,10000...其目的就是一个一个去试x中对应位置的元素是1还是0,如果是1表示当前集合中有这个元素,否则没

CF Hello2020 D. New Year and Conference

D. New Year and Conference 题意 有\(2n\)个区间,分别为\([sa_1,ea_1],[sb_1,eb_1],[sa_2,ea_2],[sb_2,eb_2],\cdots,[sa_n,ea_n],[sb_n,eb_n]\),每两个区间为一对,共\(n\)对区间.一对中的两个区间绑定在一起,从n对中选出一个子集.如果子集中某个系列(a或b)区间有区间交,而另外一个系列的区间没有区间交.如果这个情况发生在某个子集中,则输出NO,否则输出YES 分析 先考虑a系列区间交的

微软发布 Windows Server 2016 预览版第三版,开发者要重点关注Nano Server

微软已经发布 Windows Server 2016 和 System Center 2016 第三个技术预览版,已经提供下载.Windows Server 2016 技术预览版第三版也是首个包括了容器技术的支持的版本,也提供了 Nano Server 和数据中心增强的功能. Windows Server 容器是微软和 Docker 合作的,开发者可以通过隔离操作系统环境的方式来运行应用.Windows Server 容器是 Docker 开源计划的一部分,容器可以通过 PowerShell 或

Codechef WEASELTX

WEASELTX code给你一棵 n 个节点的有根树(节点),以及每个节点 i 的初始权值 a[i] .一次操作则是指将每个节点的权值变为以其为根的子树中所有节点的权值之异或和.维护 q 个询问,每个询问则是问 T 次操作之后,根节点的权值.解:相关题目:HDU 6129 http://acm.hdu.edu.cn/showproblem.php?pid=6129HDU 6129 是树退化成一条链的情形. 我们的做法依然是考虑每个节点对答案的贡献.如果是求和,则 T 次操作之后,考虑每个节点

AOJ 0033 Ball 题解 《挑战程序设计竞赛》

题目:Aizu - 0033 思路:二进制枚举,用了昨天学到的2^N以及与运算方法枚举. 1 #include <iostream> 2 #include <vector> 3 #include <algorithm> 4 5 using namespace std; 6 7 int n; 8 int ball[10]; 9 vector<int> l; 10 vector<int> r; 11 12 bool solve() { 13 bool

Windows x86/ x64 Ring3层注入Dll总结

0x01.前言 提到Dll的注入,立马能够想到的方法就有很多,比如利用远程线程.Apc等等,这里我对Ring3层的Dll注入学习做一个总结吧. 我把注入的方法分成六类,分别是:1.创建新线程.2.设置线程上下背景文,修改寄存器.3.插入Apc队列.4.修改注册表.5.挂钩窗口消息.6.远程手动实现LoadLibrary. 那么下面就开始学习之旅吧! 0x02.预备工作 在涉及到注入的程序中,提升程序的权限自然是必不可少的,这里我提供了两个封装的函数,都可以用于提权.第一个是通过权限令牌来调整权限