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

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;
}

版权声明:博主表示授权一切转载啦,不过要写上原作者哦:)

时间: 2024-11-08 03:59:06

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

Gym - 100342J Triatrip (bitset求三元环个数)

https://vjudge.net/problem/Gym-100342J 题意:给出一个邻接矩阵有向图,求图中的三元环的个数. 思路: 利用bitset暴力求解,记得最后需要/3. 1 #include<iostream> 2 #include<algorithm> 3 #include<cstring> 4 #include<cstdio> 5 #include<vector> 6 #include<stack> 7 #incl

codeforce Gym 100342J Triatrip (bitset)

傻逼题,但是为什么别人的O(n^3)不会T?只是因为用了bitset优化... 附上一张bitset基本操作的表 #include<bits/stdc++.h> using namespace std; const int maxn = 1500+2; char g[maxn][maxn]; bitset<maxn> b1[maxn],b2[maxn],res; #define local int main() { #ifdef local freopen("triatr

Gym - 100342J:Triatrip(Bitset加速求三元环的数量)

题意:求有向图里面有多少个三元环. 思路:枚举起点A,遍历A可以到的B,然后求C的数量,C的数量位B可以到是地方X集合,和可以到A的地方Y集合的交集(X&Y). B点可以枚举,也可以遍历.(两种都试过,区别不大.) 枚举代码: #include<cstdio> #include<bitset> #include<cstdlib> #include<cstring> #include<iostream> #include<algori

csu 1978: LXX的图论题

1978: LXX的图论题 Submit Page   Summary   Time Limit: 1 Sec     Memory Limit: 128 Mb     Submitted: 71     Solved: 27 Description 由于lxx的图论和数据结构太弱了,大佬Z决定为lxx补一补.于是大佬Z为lxx出了一道题目,题目如下:给出一张有向图,图中有n个点,m条边,每条边上都有一个权值w,问图中是否存在满足以下条件的点i,j,...p使得不等式w[i][j] * w[j]

CSUOJ-1978 LXX的图论题(最短路、Bellman-Ford判断负圈)

1978: LXX的图论题 Time Limit: 1 Sec     Memory Limit: 128 Mb     Submitted: 22     Solved: 9 Description 由于lxx的图论和数据结构太弱了,大佬Z决定为lxx补一补.于是大佬Z为lxx出了一道题目,题目如下:给出一张有向图,图中有n个点,m条边,每条边上都有一个权值w,问图中是否存在满足以下条件的点i,j,...p使得不等式w[i][j] * w[j][k] * .... * w[p][i]<1成立.

不会的图论题

列一下曾经做过的不会的图论题 bzoj4398: 福慧双修 bzoj4681: [Jsoi2010]旅行 NEERC 2017 Problem J Journey from Petersburg to Moscow 原文地址:https://www.cnblogs.com/tkandi/p/10556829.html

Codeforces Gym 100342J Problem J. Triatrip 求三元环的数量 bitset

Problem J. Triatrip Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/gym/100342/attachments Description The travel agency “Four Russians” is offering the new service for their clients. Unlike other agencies that only suggest one-way

Gym 100917J---Judgement(01背包+bitset)

题目链接 http://codeforces.com/gym/100917/problem/J Description standard input/outputStatements The jury of Berland regional olympiad in informatics does not trust to contest management systems, so the Berland regional programming contest is judged by th

Codeforces Gym 100342J Problem J. Triatrip 三元环

题目链接: http://codeforces.com/gym/100342 题意: 求三元环的个数 题解: 用bitset分别统计每个点的出度的边和入度的边. 枚举每一条边(a,b),计算以b为出度的边的终点构成的点集和以a为入度的边的起点够成的点集的交集,更新答案. 代码: #include<iostream> #include<cstring> #include<cstdio> #include<bitset> using namespace std;