(二进制枚举子集)买玩具

Posted xusi

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了(二进制枚举子集)买玩具相关的知识,希望对你有一定的参考价值。

问题描述
        蒜厂幼儿园有 n 个小朋友,每个小朋友都有自己想玩的玩具。身为幼儿园园长的你决定给幼儿园买一批玩具,由于经费有限,你只能买 m 个玩具。已知玩具商店一共卖 k 种玩具,编号为 1,2,3,…k,你让每个小朋友把想玩的玩具编号都写在了纸上。你希望满足尽可能多的小朋友的需求,请计算出最多同时能满足多少个小朋友的玩具需求。

输入格式
第一行,输入三个整数 n,m,k(1≤n≤100,1≤m≤k≤15),中间用空格分开。
接下来 n 行,第 i+1(0≤i< n) 行的第一个数字 ai代表第 i 个小朋友想玩的玩具数量,接下来有 ai个数字,代表这 ai 个玩具的编号。

输出格式
输出一个整数,表示最多能满足多少小朋友的玩具需求。

样例输入
5 3 5
2 1 4
0
2 3 1
3 2 3 4
2 4 5

样例输出
3
 
思路:
用二进制num[j]表示每个小朋友的需求,然后用二进制遍历i从0到(1<<k),i可以满足小朋友方案,结果加1,寻找最大可以满足的小朋友的个数

num[0]=  1001      ,1、4号玩具

num[1]=       0       ,不需要玩具

num[2]=   101      ,1、3号玩具

num[3]=  1110      ,2、3、4号玩具

num[4]=11000      ,4、5号玩具

 
位运算规矩:
技术图片

 

 

#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
const int kMax = 100 + 10;
int num[kMax];

int main() {
    int mx=0;
    int n,m,k;                            //n个小朋友 买m个玩具 共用k个玩具 
    int a,t; 
    cin>>n>>m>>k;
    for(int i=0;i<n;i++){
        int cou=0;
        cin>>a;                           //每个小朋友想要的玩具个数 
        while(a){
            cin>>t;
            cou+=(1<<(t-1));              //用二进制表示改小朋友想要的玩具方案  (1001表示想要4号和1号玩具) 
            a--;
        }
        num[i]=cou;                        //用数组保存每个小朋友想要的玩具方案 
    }
    for(int i=0;i<(1<<k);i++){             //二进制枚举 
        int count=0;
        for(int j=0;j<k;j++){
            if(i&(1<<j)) count++;          //表示求i中的1的个数 即求i方案需要玩具个数 
        }
        if(count==m){                      //满足购买的玩具等于m才符合要求 
            int peo=0;                     //每种方案满足小朋友个数 
            for(int j=0;j<n;j++){          //遍历每个小朋友的方案 是否和枚举的i方案相同 
                if((i|num[j])==i){ // |运算表示两个位有一个1,结果位就是1  (i|num[j])==i表示i方案大于等于num[j]的方案数 
                    peo++;
                }
            }
            mx=max(mx,peo);                //结果取满足最多人数的方案 
        }
    }
    cout<<mx;
    return 0;
}

 

以上是关于(二进制枚举子集)买玩具的主要内容,如果未能解决你的问题,请参考以下文章

枚举子集&高位前缀和

子集的生成—二进制枚举

二进制集合枚举子集

hihocoder #1071 : 小玩具

二进制枚举子集技巧

子集枚举的二进制算法