之前一直不知道bitset具体的原理,只知道一部分用法。
今天考了一道bitset优化的题,就抽了一些时间研究了一下bitset。
1.原理
就是二进制压位。
具体的可以看一下那道题:
在美丽的比特镇一共有n 个景区,编号依次为1 到n,它们之间通过若干条双向道路连接。
Byteasar 慕名来到了比特镇旅游,不过由于昂贵的门票费,他只能负担起4 个景区的门票费。
他可以在任意景区开始游览,然后结束在任意景区。
Byteasar 的旅游习惯比较特殊,一旦他路过了一个景区,他就一定会进去参观,并且他永远不会参观同一个景区两次。
所以他想知道,有多少种可行的旅游路线,使得他可以恰好参观4 个景区呢?即,有多少条简单路径恰好经过了4 个点。
Input
第一行包含两个整数n,表示景区的总数。
第2 至第n + 1 行,每行一个长度为n 的01 字符串,第i + 1 行第j 个字符为0 表示i 和j 之间没有道路,为1 表示有一条道路。
输入数据保证(i; j) 的连接情况等于(j; i) 的连接情况,且(i; i) 恒为0。
Output
输出一行一个整数,即可行的路线总数。
Examples
tour.in
4
0101
1010
0101
1010
tour.out
8
8 条路线分别为:
1->2->3->4,4->3->2->1,
2->3->4->1,1->4->3->2,
3->4->1->2,2->1->4->3,
4->1->2->3,3->2->1->4。
Notes
测试点编号 n
1 = 5
2 = 10
3 = 20
4 = 50
5 = 300
6 = 300
7 = 300
8 = 1500
9 = 1500
10 = 1500
标程在这里(标程手写bitset,太巨了%%%):
1 #include<cstdio> 2 const int N=1510; 3 int cnt[65536],m,n,i,j,d[N];char g[N][N];long long ans; 4 int popcount(unsigned int x){return cnt[x>>16]+cnt[x&65535];} 5 struct BIT{ 6 unsigned int v[47]; 7 void set(int x){v[x>>5]|=1U<<(x&31);} 8 void count(const BIT&b){for(int i=0;i<=m;i++)ans-=popcount(v[i]&b.v[i]);} 9 }f[N]; 10 int main(){ 11 freopen("tour.in","r",stdin);freopen("tour.out","w",stdout); 12 for(i=1;i<65536;i++)cnt[i]=cnt[i>>1]+(i&1); 13 scanf("%d",&n);m=(n-1)>>5; 14 for(i=0;i<n;i++){ 15 scanf("%s",g[i]); 16 for(j=0;j<n;j++)if(g[i][j]=='1')f[i].set(j),d[i]++; 17 } 18 for(i=0;i<n;i++)for(j=0;j<i;j++)if(g[i][j]=='1')ans+=(d[i]-1)*(d[j]-1),f[i].count(f[j]); 19 printf("%I64d",ans*2); 20 fclose(stdin);fclose(stdout); 21 return 0; 22 }
2.使用方法
定义:
bitset<666>x; //定义一个包含666位的bitset叫做x bitset<666>x(0xfa2); //赋初值 bitset<666>x(string("0101111001")); //另一种赋初值
常用函数:
x.size(); //返回x的位数 x.set(); //将x的所有位设为1 x.set(k); //将x的第k位设为1 x.set(k,a); //将第k位设为a x.reset(); //将x的所有位设为0 x.reset(k); //将x的第k位设为0 x.any(); //如果x中存在某一位是1,返回true;否则返回false x.none(); //如果x中所有位都是0,返回true;否则返回false x.count(); //返回x中1的个数 x.test(); //返回x的第k位的值 x.flip(); //翻转x的所有位的值(0变成1,1变成0) x.flip(k); //翻转x的第k位的值 x.to_ulong() //返回它转换为unsigned long的结果,如果超出范围则报错 x.to_ullong() //返回它转换为unsigned long long的结果,如果超出范围则报错 x.to_string() //返回它转换为string的结果
另外我们也可以用下标来访问、修改bitset中的位。
int res=x[3]; x[5]=1;
注意下标从0开始。
运算:
bitset的运算类似整数。
可以用==、!=、~、<<、>>、&、|、^、<<=、>>=、&=、|=、^=等运算符。
3.时间&空间&应用
可以在<bitset>头文件看出,bitset使用unsigned long进行压位的。
也就是说空间和时间都能被bitset压缩至1/32。
所以我们可以用bitset实现邻接矩阵等只含有0或1的数据结构,这样可以优化时间和空间。