2208: [Jsoi2010]连通数
Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 1879 Solved: 778
[Submit][Status][Discuss]
Description
Input
输入数据第一行是图顶点的数量,一个正整数N。 接下来N行,每行N个字符。第i行第j列的1表示顶点i到j有边,0则表示无边。
Output
输出一行一个整数,表示该图的连通数。
Sample Input
3
010
001
100
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 }