二进制枚举算法

枚举算法相信大家都不陌生,有一种特殊的枚举算法——二进制枚举

为什么要使用二进制枚举算法?

因为有的时候很难用循环把所有的情况都表示出来,二进制就可以很轻松的解决这个问题。

话不多说,看题目吧。

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;
}

 

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值