bzoj2208 [Jsoi2010]连通数(scc+bitset)

2208: [Jsoi2010]连通数

Time Limit: 20 Sec  Memory Limit: 512 MB
Submit: 1879  Solved: 778
[Submit][Status][Discuss]

Description

bzoj2208 [Jsoi2010]连通数(scc+bitset)

Input

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

Output

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

Sample Input

3
010
001
100

Sample Output

9

HINT

对于100%的数据,N不超过2000。

Source

【思路】

    强连通分量+bitset传递闭包。

    求出scc,缩点。对于新的DAG,如果两个scc之间相连则ans+=sccsz[i]*sccsz[j]。利用bitset与递推判断相连。

【代码】

 1 #include<cstdio>
 2 #include<bitset>
 3 #include<queue>
 4 #include<stack>
 5 #include<vector>
 6 #include<cstring>
 7 #include<iostream>
 8 using namespace std;
 9 
10 const int maxn = 2000+10;
11 
12 int pre[maxn],lowlink[maxn],sccno[maxn],sccsz[maxn],dfs_clock,scc_cnt;
13 vector<int> G[maxn];
14 stack<int> S;
15 
16 int dfs(int u) {
17     pre[u]=lowlink[u]=++dfs_clock;
18     S.push(u);
19     for(int i=0;i<G[u].size();i++) {
20         int v=G[u][i];
21         if(!pre[v]) {
22             dfs(v);
23             lowlink[u]=min(lowlink[u],lowlink[v]);
24         }
25         else if(!sccno[v]) {
26             lowlink[u]=min(lowlink[u],pre[v]);
27         }
28     }
29     if(lowlink[u]==pre[u]) {
30         scc_cnt++;
31         for(;;) {
32             int x=S.top(); S.pop();
33             sccno[x]=scc_cnt;
34             sccsz[scc_cnt]++;
35             if(x==u) break;
36         }
37     }
38 }
39 void find_scc(int n) {
40     memset(pre,0,sizeof(pre));
41     memset(sccsz,0,sizeof(sccsz));
42     memset(sccno,0,sizeof(sccno));
43     scc_cnt=dfs_clock=0;
44     for(int i=0;i<n;i++)  
45         if(!pre[i]) dfs(i);
46 }
47 
48 bitset<maxn> f[maxn];    //使用bitset 
49 int n,in[maxn];
50 char s[maxn];
51 
52 vector<int> Gx[maxn];
53 void rebuild() {
54     for(int i=1;i<=scc_cnt;i++) in[i]=0;
55     for(int i=0;i<n;i++) {
56         int u=sccno[i];
57         for(int j=0;j<G[i].size();j++) {
58             int v=sccno[G[i][j]];
59             if(u!=v) Gx[u].push_back(v),in[v]++;
60         }
61     }
62 }
63 
64 queue<int> q;
65 void solve() {
66     for(int i=1;i<=scc_cnt;i++) f[i][i]=1;
67     for(int i=1;i<=scc_cnt;i++) if(!in[i]) q.push(i);
68     while(!q.empty()) {
69         int u=q.front(); q.pop();
70         for(int i=0;i<Gx[u].size();i++) {
71             int v=Gx[u][i];
72             f[v]|=f[u];            //传递闭包
73             if((--in[v])==0)  q.push(v);
74         }
75     }
76 }
77 
78 int main() {
79     scanf("%d",&n);
80     for(int i=0;i<n;i++){
81         scanf("%s",s);
82         for(int j=0;j<n;j++) {
83             if(s[j]-'0') G[i].push_back(j);
84         }
85     }
86     find_scc(n);
87     rebuild();
88     solve();
89     int ans=0;
90     for(int i=1;i<=scc_cnt;i++)
91     {
92         for(int j=1;j<=scc_cnt;j++)
93             if(f[i][j]) ans+=sccsz[i]*sccsz[j];
94     }
95     printf("%d
",ans);
96     return 0;
97 }