大一寒假集训(4)----二进制枚举nefu
序:二进制枚举原理
(1)算术位运算:
(2)二进制位移操作符:
二进制枚举
1. 和为K–二进制枚举 nefu 1205
#include<bits/stdc++.h>
using namespace std;
int main()
{
int n,k;
int r;
int a[25];
while (cin>>n>>k)
{
r=0;
for (int i=0;i<n;i++)
cin>>a[i];
for (int i=0;i<(1<<n);i++)//若n为5,i为长度为5的01串,i代表的是不同的位置如011001,取的是1对应的a[j]的位置,
{
int sum=0;
for (int j=0;j<n;j++)
{
if (i&(1<<j))//&表示取余,同为1,结果为1,<<左移
sum+=a[j];
}
if (k==sum)
{
r=1;
printf("Yes\n");
break;
}
}
if (r==0)
printf("No\n");
}
return 0;
}
2.陈老师加油-二进制枚举 nefu 1505
第一重循环的左移15位是因为一共需要15位的01串.0,1分别代表路口和加油站(也可反过来)。此题中无需k来判断是否没油,因为题中条件为恰好没油。
#include <iostream>
using namespace std;
int main()
{
int t;
while (cin>>t)
{
int sum=0;
for (int i=0;i<(1<<15);i++)//1为加油站,0为路口
{
int s1=0;//加油站
int s2=0;//路口//初始化!!
int ans=t;
//int k=0;
for (int j=0;j<15;j++)
{
if (i&(1<<j))
{
s1++;
ans*=2;
}
else
{
s2++;
ans-=1;
if (ans<=0)
break;
}
}
if (s1==5&&s2==10&&ans==0)//题中为正好没油,所以无需k
sum++;
}
cout<<sum<<endl;
}
return 0;
}
3.纸牌游戏-二进制-搜索 nefu 1518
此题与第三题十分相似
#include<bits/stdc++.h>
using namespace std;
int main()
{
int n,p;
int a[25];
while (cin>>n>>p)
{
for (int i=0;i<n;i++)
cin>>a[i];
int ans=0;
for (int i=0;i<(1<<n);i++)
{
int sum=0;
for (int j=0;j<n;j++)
{
if (i&(1<<j))
{
sum+=a[j];
}
}
if (sum==p)
{
ans++;
}
}
printf("%d\n",ans);
}
return 0;
}
4.Find different nefu 1172
异或一个非常重要的性质:对于一个值异或同一个值两次,则结果还是原值。
在c/c++中异或用 ^表示。
#include<bits/stdc++.h>
using namespace std;
int main()
{
int n;
int a;
while (scanf("%d",&n)!=EOF)
{
int sum=0;
while (n--)
{
scanf("%d",&a);
sum=sum^a;//异或
}
printf("%d\n",sum);
}
return 0;
}
5.teacher Li nefu 643
1.c++/c 中都可用str.length()、str.size()、sizeof(str),都是用于求string类对象的成员函数
2.c++中有max min 函数可直接使用
3.name1.c_str( )可直接输出string 类字符串
4.C++中 ios::sync_with_stdio(false); 可提高cin 与cout的效率
#include<bits/stdc++.h>
//异或
using namespace std;
//而且在二进制中,0与任何数异或都等于那个数本身。
int main()
{
string name1;
int n;
string name2;
int r=1;//测试组数
int l1,l2;
while (cin>>n)
{
cin>>name1;
l1=name1.length();//先输入一个名字,异或
n=n*2-2;
for (int i=0;i<n;i++)
{
cin>>name2;
l2=name2.length( );
for (int j=0;j<max(l1,l2);j++)//使用最长的长度
name1[j]=name1[j]^name2[j];//异或
}
printf("Scenario #%d\n",r);
r++;
printf("%s\n\n",name1.c_str());
}
return 0;
}
6.权利指数 nefu 1641
1.memset (z,0,sizeof(z)) 注意初始化,本题有两次初始化!!
2.本题一开始一直未AC,找了半个小时bug才发现是for 语句后多了; :)我哭辽。。。。。。
3.注意格式要求。
4.单组输入。
#include<bits/stdc++.h>
using namespace std;
int main()
{
int t;
int a[25];//每个团队的票数
int b[25];//关键加入者次数
int z[25];//记录未被选出来团队
int i,j;
cin>>t;
for (int r=0; r<t; r++)
{
memset (b,0,sizeof(b));
int n;//共有n个团队
cin>>n;
int sum=0;
for (i=0; i<n; i++)
{
cin>>a[i];//输入票数
sum+=a[i];//统计总票数
}//
for (i=0; i<(1<<n); i++)
{
int k=0;
memset (z,0,sizeof(z));//注意初始化
for (j=0; j<n; j++)
{
if (i&(1<<j))
{
k+=a[j];
z[j]=1;
}
}
if (k<=sum/2)
{
for (j=0; j<n; j++)
{
if (a[j]+k>sum/2&&z[j]==0)//z[j]记录的是未被选中的数组,若满足此条件,则关键加入者次数加一。
b[j]++;
}
}
}
for (i=0; i<n-1; i++)
printf("%d ",b[i]);
printf("%d\n",b[n-1]);//注意格式
}
return 0;
}
7.趣味解题 nefu 1285
概率问题,注意三人都做对的概率算法
#include <bits/stdc++.h>
using namespace std;
int main()
{
double a[15],b[15],c[15];
double ac[15],wa[15];
int t,n,x;
int i,j;
double y1,co,sum;
cin>>t;
while (t--)
{
cin>>n;
for (i=0;i<n;i++)
cin>>a[i];
for (i=0;i<n;i++)
cin>>b[i];
for (i=0;i<n;i++)
cin>>c[i];
cin>>x;
sum=0;
for (i=0;i<(1<<n);i++)
{
y1=1;co=0;
for (j=0;j<n;j++)
{
wa[j]=(1-a[j])*(1-b[j])*(1-c[j]);//1-(三人都做错的概率)
ac[j]=1-wa[j];//做对的概率
if (i&(1<<j))
{
y1=y1*ac[j];
co++//计算做对的题数;
}
else y1=y1*wa[j];//概率公式
}
if (co==x)
sum+=y1;
}
printf("%.4lf\n",sum);
}
return 0;
}