1. 李白喝酒问题
题目描述:
话说大诗人李白,一生好饮。幸好他从不开车。一天,他提着酒壶,从家里出来,酒壶中有酒两斗。他边走边唱:
1. 无事街上走,提壶去打酒。
2. 逢店加一倍,遇花喝一斗。
这一路上,他一共遇到店5次,遇到花10次,已知最后一次遇到的是花,他正好把酒喝光了。请你计算李白遇到店和花的次序,有多少种可能得方案。
题目解析:
1. 此题求的是总的可能方案,利用dfs暴力枚举,是经常见到的方案,但是会产生很多辅助空间的浪费。
2. 利用二进制枚举是一个不错的方案,因为总共才遇店5次,遇花10次。将遇店看成二进制中的1,遇花看成二进制中的0。可以枚举出14位二进制来表示。
3.判断思路即为二进制中是否有9个0,5个1,并且最终正好剩余酒1斗。
代码如下:
int ans = 0; // 合法方案数
for(int i=0; i<(1<<14); ++i)
{
int tot_1 = 0;
int tot_0 = 0;
int num = 2;
for(int j=0; j<14; ++j)
{
if(i&(1<<j))
{
// 判断i代表的二进制中从右数第j+1位是否为1
tot_1++;
num = num*2;
}
else
{
tot_0++;
num = num-1;
}
}
if(tot_1 == 5 && tot_0 == 9 && num==1)
++ans;
}
2. 任意数之和为X的方案数。
题目描述:
某君有n个互不相同的正整数,现在他要从这n个正整数之中无重复的选取任意个数,并仅通过加法凑出整数X。求某君有多少种不同的方案来凑出整数X。其中,两个整数n,X(1<= n <= 20,1<=X<=2000),并且输入的每个整数不超过100。
题目解析:
1. 拿到此题,第一反应的暴力是求所有数的组合数,然后对每个组合判断。
2. 但是求所有数的组合数最常见的是利用递归。这个缺点就是辅助内存。
3. 可以利用二进制枚举。由题意看出,n最多为20个,那个利用20位的二进制数表示,1表示选取第i个数,0表示不选。
代码如下:
#include <iostream>
using namespace std;
int main() {
int n,X,*a;
int plan=0;
cin>>n>>X;
a=new int[n];
for(int i=0;i<n;i++)
{
cin>>a[i];
}
for(int b=0;b<(1<<n);b++)
{
int sum = 0;
for(int j=0; j<n; ++j)
{
if(b&(1<<j)) sum +=a[j];
}
if(sum == X)
++plan;
}
cout<<plan;
}
3. 买玩具满足最多小朋友需求的人数
题目描述:
幼儿园有n个小朋友,每个小朋友都有自己想玩的玩具。现在要买一批玩具,经费有限。只能买m个玩具。已知商店一共卖k种玩具,编号为1,2,3……k,你让小朋友把想玩的编号都写在了纸上。你希望尽可能满足多的小朋友的需求,请你计算最多能满足多少个小朋友的玩具需求。
输入格式:
第一行,n,m,k(1 <= n <= 100,1 <= m <= k <= 15),中间用空格分开。
接下来n行,第i+1行的第一个数字ai代表第i个小朋友想玩的玩具数量,接下来有ai个数字,代表这个玩具的编号。
输出格式:
输出一个整数,代表最多能满足多少个小朋友的玩具需求。
题目解析:
1. 看到此题的玩具总数k不超过15。应当可以想到依然使用二进制枚举的方法,设置k位二进制数,第i位为1代表第i+1个玩具买了,为0代表第i+1个玩具不买。
2. 然后先判断当前二进制数,中为1的是否为m。在比较满足的小朋友个数,最后挨个比较完后,就可以求出最大满足小朋友个数。
代码如下:
#include<iostream>
#include<vector>
#include<math.h>
using namespace std;
int main()
{
//count代表每个孩子想玩的玩具数量,toies代表每个孩子的想玩哪一种玩具
int n, m, k, count[101], toies[101][15];
cin >> n >> m >>k;
for(int i=0; i<n; ++i)
{
int x = 0;
cin >> x;
count[i] = x;
for(int j=0; j<x; ++j)
{
cin >> toies[i][j];
}
}
// 开始计算
int maxnum = 0;
int curnum = 0;
for(int i=0; i<(1<<k); ++i) // 利用二进制来代表选择哪几种玩具
{
int num = 0;
curnum = 0;
for(int j=0; j<k; ++j)
{
if(i&(1<<j))
++num;
}
if(num != m)
continue;
// 判断能够满足几个孩子的需求
for(int j=0; j<n; ++j)
{
bool bReachNeed = true;
for(int h=0; h<count[j]; ++h)
{
if((i&(1 << toies[j][h]-1)) == 0)
{
bReachNeed = false;
break;
}
}
if(bReachNeed)
++curnum;
}
if(curnum > maxnum)
maxnum = curnum;
}
cout << maxnum << endl;
return 0;
}