bitset
bitset在某些常数优化以及状态保存方面被称之为神器并不为过,主要表现在以下几个方面:
1. 状态表示。试想,用一个数来表示状态的极限是64位,而bitset可以保存任意位二进制数,并且修改简单,统计方便,并且支持批量操作。
2. 常数优化。图论的题,尤其涉及不带权的邻接图,算法经常动辄 n2,n3 ,这个时候我们可以用n个bitset存储每个点的邻接情况,并进行相应位操作,来替代直接遍历图的操作,经常可以将总复杂度降低为原来的1/32甚至还要少!
3. 集合运算。交集按位与,并集按位或,取反直接flip,简直好用。
4. 存储优化。一个bool型变量占一个字节(1byte),而bitset的一位只占1bit!某些内存卡得特别紧的情况可以试试(一般无卵用=_=
Gym 100342J Triatrip
题意:
给一个邻接矩阵,求有多少条路径可以由A出发,经过B ,再经过C,最后回到A。
思路:
无论是用邻接矩阵乘法,还是跑flyod,都是 n3 的算法,而n≤1500,直接来果断TLE。
路径为A→B→C→A,是一个三元环,我们枚举每一条B→C路径,如果用n个bitset存储每一个点的出度与入度情况,然后将B的入度与C的出度相与,统计相与后的结果有多少个1,便是有多少个三元环,累计相与结果,答案即为累计值/3,复杂度下降为O(n2?n/32),可以卡着时间过。
之所以要除以3的原因是环A→B→C→A包含了B→C→A→B,与C→A→B→C。
代码:
/*
* @author FreeWifi_novicer
* language : C++/C
*/
#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<string>
#include<map>
#include<set>
#include<vector>
#include<queue>
#include<bitset>
using namespace std;
#define clr( x , y ) memset(x,y,sizeof(x))
#define cls( x ) memset(x,0,sizeof(x))
#define mp make_pair
#define pb push_back
typedef long long lint;
typedef long long ll;
typedef long long LL;
const int maxn = 1505 ;
bitset<maxn> bit1[maxn] , bit2[maxn] , tmp ;
char s[maxn] ;
int G[maxn][maxn] ;
int main(){
freopen("triatrip.in","r",stdin);
freopen("triatrip.out","w",stdout);
//freopen("input.txt","r",stdin);
int n ;
cin >> n ;
for( int i = 0 ; i < maxn ; i++ ) bit1[i].reset() , bit2[i].reset() ;
for( int i = 0 ; i < n ; i++ ){
scanf( "%s" , s ) ;
for( int j = 0 ; j < n ; j++ ){
if( s[j] == ‘+‘ ){
G[i][j] = 1 ;
bit1[i].set(j) ;
bit2[j].set(i) ;
}
}
}
lint ans = 0 ;
for( int i = 0 ; i < n ; i++ ){
for( int j = 0 ; j < n ; j++ ){
if( i == j ) continue ;
if( G[i][j] ){
tmp = bit1[j] & bit2[i] ;
ans += tmp.count() ;
}
}
}
cout << ans / 3 << endl;
return 0;
}
Gym 100345H Settling the Universe Up
题意:
输入一个邻接矩阵,统计图中有多少对点 ( u , v ) 是从u出发可以到达v,且u < v。
同时动态增删图中路径。
思路:
看到这种问题,又想到了线段树,怒想半小时无解,卒。
先用bitset1存储每个点一次可到达点。
然后新开一组bitset2存储每个点的所有升序可到达点,bitset2可由bitset1进行或运算推出来,每次更新都重新推一次,直接暴力即可。
不得不说bitset实在神奇。。不用bitset我都不知道怎么做这道题了。
代码:
/*
* @author FreeWifi_novicer
* language : C++/C
*/
#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<string>
#include<map>
#include<set>
#include<vector>
#include<queue>
#include<bitset>
using namespace std;
#define clr( x , y ) memset(x,y,sizeof(x))
#define cls( x ) memset(x,0,sizeof(x))
#define mp make_pair
#define pb push_back
typedef long long lint;
typedef long long ll;
typedef long long LL;
const int maxn = 205 ;
bitset<maxn> bit[maxn] , bits[maxn] ;
int n , sum , m ;
void update(){
for( int i = 1 ; i <= n ; i++ ) bits[i].reset() ;
sum = 0 ;
for( int i = n ; i > 0 ; i-- ){
bits[i].set(i);
for( int j = 1 ; j < i ; j++ ){
if( bit[j][i] )
bits[j] |= bits[i] ;
}
sum += bits[i].count() ;
}
}
int main(){
// freopen("input.txt","r",stdin);
freopen("settling.in","r",stdin);
freopen("settling.out","w",stdout);
cin >> n >> m ;
for( int i = 1 ; i <= n ; i++ ) bit[i].reset() , bits[i].reset() ;
for( int i = 0 ; i < m ; i++ ) {
int u , v ;
scanf( "%d%d" , &u , &v ) ;
bit[u].set(v);
}
sum = 0 ;
update() ;
printf( "%d\n" , sum - n ) ;
int k ; cin >> k ;
while( k-- ){
char op[2] ;
int u , v ;
scanf( "%s%d%d" , op , &u , &v ) ;
if( op[0] == ‘+‘ ){
bit[u].set(v) ;
update() ;
printf( "%d\n" , sum - n ) ;
}
else if( op[0] == ‘-‘ ){
bit[u].reset(v) ;
update() ;
printf( "%d\n" , sum - n ) ;
}
else {
if( bits[u].test(v) )
puts( "YES" ) ;
else
puts( "NO" ) ;
}
}
return 0;
}
版权声明:博主表示授权一切转载啦,不过要写上原作者哦:)