天天看點

【BZOJ2208】【JSOI2010】連通數 傳遞閉包

題目描述

  定義一個圖的連通度為圖中可達頂點對的數目。給你一個 n 個點的有向圖,問你這個圖的連通度。

  n≤2000,m≤n2

題解

  一個很簡單的做法就是傳遞閉包:像floyd算法一樣處理兩個點之間是否可達。

fi,j|=fi,k&fk,j

  但是這是 O(n3) 的。

  觀察到用到的運算都是位運算,那就用bitset加速一下就行了。

  時間複雜度: O(n364) (還是 O(n3) )

代碼

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<ctime>
#include<utility>
#include<cmath>
#include<functional>
#include<bitset>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
void sort(int &a,int &b)
{
    if(a>b)
        swap(a,b);
}
void open(const char *s)
{
#ifndef ONLINE_JUDGE
    char str[];
    sprintf(str,"%s.in",s);
    freopen(str,"r",stdin);
    sprintf(str,"%s.out",s);
    freopen(str,"w",stdout);
#endif
}
int rd()
{
    int s=,c;
    while((c=getchar())<'0'||c>'9');
    do
    {
        s=s*+c-'0';
    }
    while((c=getchar())>='0'&&c<='9');
    return s;
}
int upmin(int &a,int b)
{
    if(b<a)
    {
        a=b;
        return ;
    }
    return ;
}
int upmax(int &a,int b)
{
    if(b>a)
    {
        a=b;
        return ;
    }
    return ;
}
bitset<2001> f[];
char s[];
int main()
{
    int n;
    int i,j;
    scanf("%d",&n);
    for(i=;i<=n;i++)
    {
        scanf("%s",s+);
        for(j=;j<=n;j++)
            if(s[j]-'0')
                f[i].set(j);
        f[i].set(i);
    }
    for(j=;j<=n;j++)
        for(i=;i<=n;i++)
            if(i!=j&&f[i][j])
                f[i]|=f[j];
    int s=;
    for(i=;i<=n;i++)
        s+=f[i].count();
    printf("%d\n",s);
    return ;
}