2208: [Jsoi2010]连通数
Time Limit: 20 Sec Memory Limit: 512 MB
Submit: 1489 Solved: 606
[Submit][Status][Discuss]
Description
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
#include<iostream> #include<cstdio> #include<cstring> #include<string> #include<cmath> #include<string> #include<algorithm> #include<bitset> #include<queue> #include<vector> #include<stack> using namespace std; vector<int> e[2005],g[2005]; stack<int> s; bitset<2005> f[2005]; int n,mp[2005][2005]; int Dfs[2005],low[2005],use[2005],top,newflag,isstack[2005],in[2005],num[2005]; bool vis[2005][2005]; void tarjan(int u) { Dfs[u]=low[u]=++top; isstack[u]=1; s.push(u); for(int i=0;i<e[u].size();i++) { int v=e[u][i]; if(!Dfs[v]) { tarjan(v); low[u]=min(low[u],low[v]); } else if(isstack[v]) low[u]=min(low[u],Dfs[v]); } if(low[u]==Dfs[u]) { newflag++; int x; do { x=s.top(); s.pop(); isstack[x]=0; use[x]=newflag; num[newflag]++; }while(x!=u); } } void topsort() { queue<int> q; for(int i=1;i<=newflag;i++) { f[i][i]=1; if(in[i]==0) q.push(i); } while(!q.empty()) { int x=q.front(); q.pop(); for(int i=0;i<g[x].size();i++) { int v=g[x][i]; f[v]=f[v]|f[x]; if(--in[v]==0) q.push(v); } } } int main() { scanf("%d",&n); for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++) { scanf("%1d",&mp[i][j]); if(i!=j&&mp[i][j]) e[i].push_back(j); } } for(int i=1;i<=n;i++) { if(!Dfs[i]) tarjan(i); } for(int i=1;i<=n;i++) { for(int j=0;j<e[i].size();j++) { int u,v; u=i,v=e[i][j]; if(use[u]!=use[v]&&!vis[use[u]][use[v]]) { g[use[u]].push_back(use[v]); vis[use[u]][use[v]]=1; in[use[v]]++; } } } topsort(); int ans=0; for(int i=1;i<=newflag;i++) { for(int j=1;j<=newflag;j++) { if(f[i][j]) ans+=num[i]*num[j]; } } printf("%d\n",ans); return 0; }
时间: 2024-10-15 20:17:47