「这是我参与2022首次更文挑战的第3天,活动详情查看:2022首次更文挑战」。
蓝桥杯刷题有很多搜索问题,如果是将一组数据分成两组,找出其中一个满足特定条件的分成了两组的数据。这里就可以用到状态压缩搜索。状态压缩后用位运算进行搜索。位运算搜索有多快相信大家都有所了解。
状态压缩
这里状态压缩是指将每一个数据都可以单独用一串二进制数来表示。例如在一个数组从下标0开始存储n个数字,那么二进制数0代表的就是下标为0的这个数,二进制数1代表的就是下标为1的这个数,二进制10代表的就是下标为2的这个数,以此类推。
搜索
通过位运算来搜索,可以遍历所有的情况,虽然和暴力枚举类似,但是效率和速度要快不少。
算法实例
给N根木棍,将这N根木棍分成两组,两组木棍分别拼接在一起成为两根长木棍,而且这两组的木棍要一样长。要求找出这种情况下最长的两根。 代码分成两部分,第一部分为第一组的所有情况,第二部分分为第二组的所有情况。 N<10000。
第一部分
#include<bits/stdc++.h>
using namespace std;
int a[100010],b[100010];
int main(){
int n;
cin>>n;
int ans=0;
for(int i=0;i<n;i++){
cin>>b[i];
}
for(int i=0;i<(1<<n);i++){
for(int j=0;j<n;j++){
if(i&(1<<j))
a[i]+=b[j];
}
}
这一部分可以得出所有在N个木棍选取不超过N-1根木棍的组合。并且可以用另一个数组来存储这些组合的长度。
第二部分
for(int i=0;i<(1<<n);i++){
int tem=(1<<n)-1-i;
for(int j=tem;j>0;j=(j-1)&tem)
if(a[i]==a[j]){
ans=max(ans,a[i]);
}
}
cout<<ans;
return 0;
这一部分就是上个部分组合的补集,得出的就是第二组。最后和第一组比较是否相等最后得出最大的组合。
总结
这类题目的要点是能否用二进制数代表一个数据,如果可以,那么就判断能否用位运算的遍历来完成分组,如果可以,可以试着用状态压缩来完成这类题目。