bzoj 2208(强连通)

2208: [Jsoi2010]连通数

Time Limit: 20 Sec   Memory Limit: 512 MB
Submit: 2028   Solved: 855
[ 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。


解题思路:先强连通分量求出来,然后每一个分量bfs一遍(我只会这个)


#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;
int n,len,len1,head,tail,size,tcc;
int to[4000011],next[4000011],h[2010];
int to1[4000011],next1[4000011],h1[2010];
int q[4000011];
int dfn[2010],twf[2010];
int biao[2010],dui[2010],sg[2010];
bool b[2010][2010];
int ru[2010];
int sum[2010];
bool g[2010];


inline int read()
{
char y; int x=0,f=1; y=getchar();
while (y<'0' || y>'9') {if (y=='-')f=-1; y=getchar();}
while (y>='0' && y<='9') {x=x*10+int(y)-48; y=getchar();}
return x*f;
}


void insert(int x,int y) 
{
++len; to[len]=y; next[len]=h[x]; h[x]=len;
}


void insert1(int x,int y)
 {
  ++len1; to1[len1]=y; next1[len1]=h1[x]; h1[x]=len1;
 }


void dfs(int x,int fa)
 {
  ++head; q[head]=x;
  ++size; dfn[x]=twf[x]=size; biao[x]=1;
  int u=h[x];
  while (u!=0)
  {
  if (to[u]!=fa && dfn[to[u]]==-1)
  {
  dfs(to[u],x);
  twf[x]=min(twf[x],twf[to[u]]);
}else
 if (biao[to[u]]==1) twf[x]=min(twf[x],twf[to[u]]);
u=next[u];
}
    if (twf[x]==dfn[x])
     {
        ++tcc;
        while (q[head]!=x)
         {
          biao[q[head]]=2;
          dui[q[head]]=tcc; ++sg[tcc];
          --head;
}
biao[x]=2;
dui[x]=tcc; ++sg[tcc]; --head; sum[tcc]=sg[tcc];
}
 }


int main()
{
n=read();
for (int i=1;i<=n;++i)
{
char c[2100];
scanf("%s",c);
int len=strlen(c);
for (int j=1;j<=len;++j)
if (c[j-1]=='1')
 {
 insert(i,j); 
 }
}
tcc=0; size=0; head=0;
memset(twf,-1,sizeof(twf));
memset(dfn,-1,sizeof(dfn));
memset(biao,-1,sizeof(biao));
for (int i=1;i<=n;++i)
if (dfn[i]==-1)
 {
  dfs(i,0);
 }
memset(b,true,sizeof(b));
for (int i=1;i<=n;++i)
{
int u=h[i];
while (u!=0)
{
  if (b[dui[i]][dui[to[u]]]==true && dui[to[u]]!=dui[i])
   {
   b[dui[i]][dui[to[u]]]=false;
   insert1(dui[i],dui[to[u]]);
}
u=next[u];
}
}
long long ans=0;
for (int i=1;i<=tcc;++i)
{
memset(g,true,sizeof(g));
int head=0,tail=1; q[tail]=i; g[i]=false;
while (head<tail)
{
++head;
ans+=sg[i]*sg[q[head]];
int u=h1[q[head]];
while (u!=0)
{
 if (g[to1[u]])
  {
 g[to1[u]]=false; ++tail; q[tail]=to1[u];
}
  u=next1[u];
}
}
}

printf("%lld",ans);
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值