BZOJ 2208: [Jsoi2010]连通数 Tarjan

2208: [Jsoi2010]连通数

Description

Input

输入数据第一行是图顶点的数量,一个正整数N。 接下来N行,每行N个字符。第i行第j列的1表示顶点i到j有边,0则表示无边。

Output

输出一行一个整数,表示该图的连通数。

Sample Input

3
010
001
100

Sample Output

9

思路 :

  tarjan  + 拓扑排序 + dp + STL:: bitset 优化 f[i][j]表示从i到j这种状态的答案, 把jbitset压一个32就可以过了

代码:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <stack>
#include <bitset>
#include <queue>
using namespace std;
const int N = 2100, M = 4001000;
int head[N], to[M], nxt[M], cnt;
int dfn[N], low[N], place[N], val[N], idx, tot;
int map[N][N];
bool vis[N][N];
int ind[N];
stack<int>s;
bitset<N> f[N];
int ins[N];
void add(int x, int y) {
    to[++cnt] = y;
    nxt[cnt] = head[x];
    head[x] = cnt;
}
void Tarjan(int p) {
    dfn[p] = low[p] = ++idx;
    ins[p] = 1;s.push(p);
    for(int i=head[p];i;i=nxt[i]) {
        if(!dfn[to[i]]) {
            Tarjan(to[i]);
            low[p] = min(low[p], low[to[i]]);
        }
        else if(ins[to[i]]) {
            low[p] = min(low[p], dfn[to[i]]);
        }
    }
    if(dfn[p]==low[p]) {
        int t = 0;
        tot++;
        while(t!=p) {
            t = s.top();s.pop();
            ins[t] = 0;
            place[t] = tot;
            val[tot]++;
        }
    }
}
int n;
void rebuild() {
    memset(head, 0, sizeof(head));
    cnt = 0;
    for(int i=1;i<=n;i++) {
        for(int j=1;j<=n;j++) {
            if(map[i][j]&&place[i]!=place[j])
                ind[place[i]]++,add(place[j], place[i]);
        }
    }
    for(int i=1;i<=tot;i++) f[i][i]=1;
}
int ans = 0;
void topo() {
    queue<int>q;
    for(int i=1;i<=tot;i++) if(!ind[i]) q.push(i);
    while(!q.empty()) {
        int u = q.front();q.pop();
        for(int i=head[u];i;i=nxt[i]) {
            ind[to[i]]--;
            f[to[i]]|=f[u];
            if(!ind[to[i]])q.push(to[i]);
        }
    }
    for(int i=1;i<=tot;i++) {
        for(int j=1;j<=tot;j++) {
            if(f[i][j]) ans += val[i] * val[j];
        }
    }
}
int main() {
    scanf("%d", &n);
    for(int i=1;i<=n;i++) {
        for(int j=1;j<=n;j++) {
            scanf("%1d", &map[i][j]);
            if(map[i][j]) add(i, j);
        }
    }
    for(int i=1;i<=n;i++) {
        if(!dfn[i]) Tarjan(i);
    }
    rebuild();
    topo();
    printf("%d
", ans);
}
原文地址:https://www.cnblogs.com/Tobichi/p/9230750.html