版权声明:辛辛苦苦码字,你们转载的时候记得告诉我 https://blog.csdn.net/dxyinme/article/details/83421676
Time Limit: 20 Sec
Memory Limit: 512 MB
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。
题解:
既然n<=2000那就n方算法干过去咯,tarjan缩环重建图,然后在DAG上跑dfs求每个点的联通数。刚好两次
///本来跟队友说我要练思维…结果脑子不行还是练手速来了。
#include<bits/stdc++.h>
#define LiangJiaJun main
#define ll long long
using namespace std;
struct edge{
int to,nt;
}e[4000004];
int h[2004],n,m,ne;
char mp[2004][2004];
bool inq[2004],vis[2004];
int cnt,belong[2004],scc,low[2004],dfn[2004],sz[2004],ru[2004];
stack<int>st;
void add(int u,int v){
e[++ne].to=v;e[ne].nt=h[u];
h[u]=ne;
}
void dfs(int x){
dfn[x]=low[x]=++cnt;
inq[x]=1;
st.push(x);
for(int i=1;i<=n;i++){
if(mp[x][i]=='0')continue;
if(!dfn[i]){
dfs(i);
low[x]=min(low[x],low[i]);
}
else if(inq[i]){
low[x]=min(low[x],dfn[i]);
}
}
if(low[x]==dfn[x]){
int now=-1;
scc++;
while(now!=x){
now=st.top();st.pop();
sz[scc]++;
inq[now]=0;
belong[now]=scc;
}
}
}
void rebuild(){
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(mp[i][j]=='0')continue;
if(belong[i]!=belong[j]){
add(belong[i],belong[j]);
++ru[belong[j]];
}
}
}
}
int f[2004];
int calc(int x){
vis[x]=1;
int res=0;
for(int i=h[x];i;i=e[i].nt){
if(!vis[e[i].to])res+=calc(e[i].to);
}
res+=sz[x];
return res;
}
int w33ha(){
scc=0;cnt=0;
memset(ru,0,sizeof(ru));
memset(belong,0,sizeof(belong));
memset(low,0,sizeof(low));
memset(dfn,0,sizeof(dfn));
memset(sz,0,sizeof(sz));
memset(f,0,sizeof(f));
ne=0;
memset(h,0,sizeof(h));
for(int i=1;i<=n;i++)scanf("%s",mp[i]+1);
for(int i=1;i<=n;i++){
if(!dfn[i]){
dfs(i);
}
}
rebuild();
ll ans=0;
for(int i=1;i<=scc;i++){
for(int j=1;j<=scc;j++)vis[j]=0;
ans+=1LL*sz[i]*calc(i);
}
printf("%lld\n",ans);
return 0;
}
int LiangJiaJun(){
while(scanf("%d",&n)!=EOF)w33ha();
return 0;
}