枚举算法相信大家都不陌生,有一种特殊的枚举算法——二进制枚举
为什么要使用二进制枚举算法?
因为有的时候很难用循环把所有的情况都表示出来,二进制就可以很轻松的解决这个问题。
话不多说,看题目吧。
1.话说大诗人李白,一生好饮。幸好他从不开车。
一天, 他提着酒壶,从家里出来,酒壶中有酒两斗。他边走边唱:
无事街上走,提壶去打酒。
逢店加一倍,遇花喝一斗。
这一路上,他一共遇到店 5 次,遇到花 10 次,已知最后一次遇到的是花,他正好把酒喝
光了。请你计算李白遇到店和花的次序,有多少种可能的方案?
这个题目解法很多,二进制枚举是一种写起来非常简洁的解法。我们已知遇店 5 次,遇花
10 次,并且最后一次遇到花,正好把酒喝光。那么我们可以把店作为二进制中的 1,把花
作为二进制中的 0,因为已经确定最后一次遇到的是花,所以我们需要判断枚举的结果是否
刚好有 5 个 1 和 9 个 0。那么我们就枚举出 14 位二进制的所有可能并加以判断即可,
判断思路为判断二进制是否有 9 个 0,5 个 1,并且最终酒刚好剩 1 斗。
源码:
# include <cstdio>
# include <algorithm>
using namespace std;
int main ()
{
int p=0;
for (int i=0;i<(1<<14);++i) // i=0,i可以有15位2进制
{
int t0=0;
int t1=0;
int s=2;
for (int j=0;j<14;++j)
{
if (i&(1<<j)) // 首先1向左移j位,就是判断i的j+1位是1还是0;
{
t1++;
s=s*2;
}
else
{
t0++;
s=s-1;
}
}
if (s==1 && t1==5 && t0==9) //别忘了最后的判断条件是三个,缺一不可。
p++;
}
printf ("%d\n",p);
return 0;
}
2.slands 最近在完一款游戏“炉石传说”,又名“魔兽英雄传”。炉石传说是一款卡牌类对
战的游戏。游戏是两人对战,总的来说,里面的卡牌分成两类,一类是法术牌,另一类是随
从牌(所谓随从就是怪物)。
为了简化问题,现在假设随从牌的作用是召唤一个具有一定攻击力的怪物,法术牌的作用是
给某个随从增加一定攻击力。随从牌和法术牌的使用都需要消耗一定的法力值。现在
islands 有 10 点法力值,手上有 n 张牌(islands 最多有 10 张牌,否者他将会被爆牌
T_T),有些是法术牌,有些是随从牌。islands 现在是大劣势,他想要是利用这 10 点法力
值使得召唤出来的所有随从的攻击力总和最高(法力值可以不用完)。注意,任何法术牌都
必须使用在某个召唤出来的随从上,也就是如果 islands 没有召唤过随从,他将不能使用
任何法术牌。告诉 islands 他能召唤的随从的总攻击力最大是多少。
输入格式
每组数据首先输入一个 n(0≤n≤10,表示 islands 有 n 张牌。
接下来 n 行,每行输入 3 个整数 cost(0≤cost≤10),d(0 或者 1),w(∣w∣≤1000)。
其中 cost 表示该牌的法力值消耗,
如果 d=0,表示该牌是攻击力为 w 的随从牌;
如果 d=1,表示是能给一个随从增加 w 攻击的法术牌。
输出格式
输出一行表示答案。
样例输入
1 0 100
样例输出
100
# include <bits/stdc++.h>
using namespace std;
struct node
{
int c;
int d;
int w;
}s[100];
int main ()
{
int n;
int maxn=-1000;
scanf ("%d",&n);
for (int i=0;i<n;++i) cin>>s[i].c>>s[i].d>>s[i].w;
for (int i=0;i<(1<<n);++i) // 卡牌取的所有情况用二进制去表示
{
int flag=0;
int sum=0;
int t=0;
for (int j=0;j<n;++j) //把其中的一位二进制,拆开来分析,二进制每个位上面的情况
{
if (i&(1<<j)) //1就是取到这张牌
{
if (s[j].d==0) flag=1; //控制一下条件
sum=sum+s[j].w;
t=t+s[j].c;
}
}
if (t>10) continue;//控制一下循环退出的条件,看一看满不满足。
if (flag==0) continue;//
maxn=max(maxn,sum);
}
printf ("%d\n",maxn);
return 0;
}