【Aizu-ITP2_11_B】解题报告(二进制枚举)

原始题目

Aizu-ITP2_11_B Aizu原始题面

Aizu-ITP2_11_B Vj题面

题目大意

给定集合大小,同时给定一个子集k,要求输出子集包含该子集k。同时输出其在原集合所有子集中的二进制序编号,根据二进制编号从小到大依次输出符合的子集。

解题思路

本题$n≤18$还可以枚举全部子集计数求其编号,对于每个子集判断是否包含所有要求包含元素(该位与运算),满足的话最后输出。

解题代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;

ll checknum[100], n, m;

#define rep(i, a, n) for (ll i = a; i < n; ++i)
#define per(i, a, n) for (ll i = n - 1; i >= a; --i)

void print_subset(ll n, ll m)
{
ll ans = 0;
rep(i, 0, (1 << n))
{
ans++;
int flag = 1;
rep(j, 0, m)
{
//注意位运算的顺序
if (((1 << checknum[j]) & i) == 0) {
flag = 0;
break;
}
}
if (!flag)
continue;
cout << ans - 1 << ":";
rep(j, 0, n)
{
if ((1 << j) & i)
cout << " " << j;
}
cout << endl;
}
}

int main()
{
ios::sync_with_stdio(false);
while (cin >> n) {
memset(checknum, 0, sizeof(checknum));
cin >> m;
rep(i, 0, m) cin >> checknum[i];
print_subset(n, m);
}
}

收获与反思

枚举子集常见的思路,参见。