二进制枚举子集

来源:互联网 发布:苹果拍照软件搞怪 编辑:程序博客网 时间:2024/05/22 12:09

思路:

 利用二进制的“开关”特性枚举; 具体为:假设给定集合A大小为n,则想象A = {a[0], a[1], ..., a[n-1]}的每个元素对应一个开关位(0或1),0表示不出现,1表示出现; 当每个元素的开关位的值确定时,就得到一个子集,因此共有2^n-1种情况(全0为空集,这里不考虑); 我们利用区间[1, 2^n-1],该区间上的每一个整数对应一个子集,对应方法是遍历该整数二进制表示的每一位; 若该位为1则相应子集中存在对应元素,否则不存在。

代码:

#include <bits/stdc++.h>//二进制法using namespace std;void print_subset(int n, int s){    for (int i = 0; i < n; i++)        if (s & (1 << i))            cout << i << " ";    cout << endl;}int main(int argc, char const *argv[]){    int n;    while (cin >> n && n)        for (int i = 0; i < (1 << n); i++)            print_subset(n, i);    return 0;}

CF #306 (Div. 2) B. Preparing Olympiad

题意:
  给你一个数组,求满足子集的个数:  满足的条件: 子集中所有元素的和不超过给定的l 和 r ;             最大值-最小值 < x;
代码:
#include<iostream>#include<cstdio>#include<cstring>#include<math.h>using namespace std;#define LL long long#define clr(a,b) memset(a,b,sizeof a)int n,l,r,x;int A[26];int main(){    #ifndef ONLINE_JUDGE    freopen("in.txt","r",stdin);    freopen("out.txt","w",stdout);    #endif // ONLINE_JUDGE     while(~scanf("%d%d%d%d",&n,&l,&r,&x))     {         for(int i=0; i<n; i++){            scanf("%d",&A[i]);         }         int m=1<<n;         int cnt=0;         for(int i=0; i<m; i++){            int Max=-1;            int Min=0x3f3f3f3f;            int s=0;            for(int j=0; j<n; j++){                if(i&(1<<j)){                    s+=A[j];                    if(A[j]>Max)  Max=A[j];                    if(A[j]<Min)  Min=A[j];                }            }            if(s>=l&&s<=r&&Max-Min>=x)  cnt++;         }         printf("%d\n",cnt);     }    return 0;}
0 0
原创粉丝点击