您的位置:首页 > 其它

Gym 100342J & Gym 100345H (bitset在图论题的应用)

2015-08-30 23:24 357 查看

bitset

bitset在某些常数优化以及状态保存方面被称之为神器并不为过,主要表现在以下几个方面:

1. 状态表示。试想,用一个数来表示状态的极限是64位,而bitset可以保存任意位二进制数,并且修改简单,统计方便,并且支持批量操作。

2. 常数优化。图论的题,尤其涉及不带权的邻接图,算法经常动辄 n2,n3n^2,n^3 ,这个时候我们可以用n个bitset存储每个点的邻接情况,并进行相应位操作,来替代直接遍历图的操作,经常可以将总复杂度降低为原来的1/32甚至还要少!

3. 集合运算。交集按位与,并集按位或,取反直接flip,简直好用。

4. 存储优化。一个bool型变量占一个字节(1byte),而bitset的一位只占1bit!某些内存卡得特别紧的情况可以试试(一般无卵用=_=

Gym 100342J Triatrip

题意:

给一个邻接矩阵,求有多少条路径可以由A出发,经过B ,再经过C,最后回到A。

思路:

无论是用邻接矩阵乘法,还是跑flyod,都是 n3n^3 的算法,而n≤1500n\leq 1500,直接来果断TLE。

路径为A→B→C→A,是一个三元环,我们枚举每一条B→C路径,如果用n个bitset存储每一个点的出度与入度情况,然后将B的入度与C的出度相与,统计相与后的结果有多少个1,便是有多少个三元环,累计相与结果,答案即为累计值/3,复杂度下降为O(n2∗n/32)O(n^2*n/32),可以卡着时间过。

之所以要除以3的原因是环A→B→C→A包含了B→C→A→B,与C→A→B→C。

代码:

[code]/*
 * @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我都不知道怎么做这道题了。

代码:

[code]/*
 * @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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: