二进制枚举

二进制枚举(自用)

原理讲解

利用二进制只有0与1来表示成立与否,枚举出所有情况

二进制知识点

在这里插入图片描述

在这里插入图片描述

for(int i=0;i<(1<<n);i++)//n个选项
for(int j=0;j<n;j++)//从第一个选项开始遍历
if(i$(1<<j)) count++;//若同为1,便加加

陈老师加油-二进制枚举
典型的二进制枚举
代码实现如下

#include <bits/stdc++.h>

using namespace std;
int t,x,y,i,j,n=0,b;
int main()
{
    scanf("%d",&b);
   for(i=0; i<(1<<15); i++)//路口与加油站一共15个,也就是15个01选项
      {        x=0;
               y=0;
               t=b;
           for(j=0; j<15; j++)
        {
            if(i&(1<<j))
            {
                t*=2;
                x++;
            }
            else
            {
                t-=1;
                y++;
            }
            if(t<=0) break;//燃油耗尽即break
        }
        if(t==0&&x==5&&y==10)//满足题目条件
            n++;
      }
      printf("%d\n",n);

    return 0;
}

权利指数
在这里插入图片描述

#include <bits/stdc++.h>

using namespace std;

int main()
{
    int n,a[22],b[22]= {0},sum,sum1,sum2,t;
   cin>>t;
   for(int k=0;k<t;k++)
    {    cin>>n;
        sum=0;
         memset(b,0,sizeof(b));//重置b数组,以免输出错误
        for(int i=0; i<n; i++)
        {
            scanf("%d",&a[i]);
            sum+=a[i];
        }
        sum=sum/2;
        for(int i=0; i<(1<<n); i++)
        {
            sum1=0;
            for(int j=0; j<n; j++)//遍历出所有组合
            {
                if(i&(1<<j)) sum1+=a[j];
            }
            if(sum1>sum)//如大于半数
            {

                for(int j=0; j<n; j++)
                {     sum2=sum1;
                    if(i&(1<<j))
                    {
                        sum2-=a[j];
                        if(sum2<=sum)//关键处理,如减去后小于半数,即为关键者一次
                            b[j]++;//进行计数(故前面需要清0)
                    }
                }
            }

        }
        for(int i=0;i<n;i++)
        {
            if(i!=n-1) printf("%d ",b[i]);
            else printf("%d\n",b[i]);
        }
    }

    return 0;
}

趣味解题
在这里插入图片描述

#include <bits/stdc++.h>
using namespace std;
int main()
{
      int n,t,cot,x;

      double ans,a[14],b[14],c[14],p,ac[14],wa[14];
      cin>>t;
      while(t--)
      {    ans=0;
          cin>>n;
          for(int i=0;i<n;i++)
            cin>>a[i];
            for(int i=0;i<n;i++)
            cin>>b[i];
            for(int i=0;i<n;i++)
            cin>>c[i];
            cin>>x;
         for(int i=0;i<(1<<n);i++)
         {
             p=1;cot=0;//概率,计数清0
             for(int j=0;j<n;j++)
             {
                 wa[j]=((1-a[j])*(1-b[j])*(1-c[j]));//算出未ac概率
                 ac[j]=1-wa[j];//ac概率
                 if(i&(1<<j))
                 {
                     p=p*ac[j]; cot++;//如遍历至此题ac则乘上ac概率,否则*wa概率
                 }
                 else p=p*wa[j];
             }
             if(cot==x)
               ans+=p;
         }
          printf("%.4lf\n",ans);
      }
}

Find different
在这里插入图片描述
此题为二进制异或典型题
所谓异或,即为
在这里插入图片描述
代码实现如下

#include <bits/stdc++.h>

using namespace std;
 int n,ans,a;
int main()
{
   while(scanf("%d",&n)!=EOF)
   {
       scanf("%d",&ans);
       n--;
       while(n--)
       {
           scanf("%d",&a);
           ans=ans^a;//将输入的每一个数异或,便能得到奇数次的数
       }
       printf("%d\n",ans);
   }
    return 0;
}

讲到异或此处再献上一题
在这里插入图片描述
n−x=n^x 这是题目中式子的变形,异或运算让我们联想到二进制,于是就用二进制来思考这道题,发现当n的k位为0时,那么x为1时,不相等,x为0时相等,当k=1时,x=0与x=1均成立,所以,只需将n转化二进制,看其有多少1,即乘以相应的2即可,代码实现如下,先是蒟蒻的版本,再是指点版

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll n;
int main()
{
    int p[35],k,m;
    p[0]=1;
    for(int i=1;i<31;i++)
        p[i]=p[i-1]*2;//先打表,预处理出所有的情况
    while(scanf("%lld",&n)!=EOF)
    {         m=0;
        for(int i=1;i<35;i++)
        {
            if(p[i]>n)
                {k=i-1;
            break;}//这一步处理,即可得到输入n的二进制位数
        }
        for(int i=0;i<=k;i++)
        {
            if(n&1<<i) m++;//进行&运算,判断1,并计数

        }
        printf("%d\n",p[m]);
    }
}

下面时位数运算

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

int main()
{
    int n,cnt;
    while(scanf("%d",&n)!=EOF)
    {
        cnt=0;
        while(n)//当n=0时退出
        {
            if(n&1) cnt++;//从右比到左,进行&,与上不同的是,此时时移动n的位数
            n>>=1;//每比一次,将n右移一位,注意不要写成n>>1(我的错)
        }
        printf("%d\n",1<<cnt);//输出2的cnt次方
    }
}

鸣谢@清风拂山岗AC的指导

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值