[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