首页 > 代码库 > BZOJ 2208 JSOI 2010 连通数 Tarjan+bitset

BZOJ 2208 JSOI 2010 连通数 Tarjan+bitset

题目大意:给出一张有向图,若一个点能够到达另一个点,那么说这两个点是一对联通点。问图中共有多少联通点。


思路:先进行一次Tarjan,求出所有的scc,对于一个scc中的点,对答案的贡献就是cnt^2,不同的scc组成了一张可拓扑图,然后对于每个scc维护一个bitset,来统计他自己和标号比它小的scc中共有多少个不同的点。然后进行dp,其中不停的或就可以了。

第一次使用bitset


CODE:


#include <bitset>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define MAXP 2010
#define MAX 4000010
using namespace std;
 
int points;
int head[MAXP],total;
int next[MAX],aim[MAX];
 
inline void Add(int x,int y)
{
    next[++total] = head[x];
    aim[total] = y;
    head[x] = total;
}
 
int dfn[MAXP],low[MAXP],_clock;
int stack[MAXP],top;
bool in_stack[MAXP];
int changed[MAXP],scc,num[MAXP];
bitset<MAXP> have[MAXP];
 
void Tarjan(int x)
{
    dfn[x] = low[x] = ++_clock;
    stack[++top] = x;
    in_stack[x] = true;
    for(int i = head[x]; i; i = next[i]) {
        if(!dfn[aim[i]])
            Tarjan(aim[i]),low[x] = min(low[x],low[aim[i]]);
        else if(in_stack[aim[i]])
            low[x] = min(low[x],dfn[aim[i]]);
    }
    if(dfn[x] == low[x]) {
        int temp;
        ++scc;
        do {
            temp = stack[top--];
            in_stack[temp] = false;
            changed[temp] = scc;
            ++num[scc];
        }while(temp != x);
    }
}
 
int main()
{
    cin >> points;
    for(int i = 1; i <= points; ++i)
        for(int x,j = 1; j <= points; ++j) {
            scanf("%1d",&x);
            if(x)   Add(i,j);
        }
    for(int i = 1; i <= points; ++i)
        if(!dfn[i]) Tarjan(i);
    for(int i = 1; i <= points; ++i)
        have[changed[i]][i] = true;
    int ans = 0;
    for(int i = 1; i <= scc; ++i) {
        ans += num[i] * num[i];
        bitset<MAXP> temp;
        for(int x = 1; x <= points; ++x)
            if(changed[x] == i)
                for(int j = head[x]; j; j = next[j])
                    if(changed[aim[j]] != i)
                        temp |= have[changed[aim[j]]];
        ans += num[i] * temp.count();
        have[i] |= temp;
    }
    cout << ans << endl;
    return 0;
}


BZOJ 2208 JSOI 2010 连通数 Tarjan+bitset