​http://www.elijahqi.win/archives/964​​​
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。

有点像此前做过的一题floyd 第一次用bitset 啊

为什么倒序做

因为我们tarjan的时候给的序号是递归给的啊,所以拓扑排序完,序号大的其实是真正图中层数小的

#include<cstdio>
#include<stack>
#include<bitset>
#include<queue>
#define N 2200
using namespace std;
inline int read(){
int x=0,f=1;char ch=getchar();
while (ch<'0'||ch>'9') {if (ch=='-') f=-1;ch=getchar();}
while (ch<='9'&&ch>='0'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
stack<int> q;queue<int> qq;
bitset<N> f[N];char s1[N];
int dfn[N],low[N],tp[N],map[N][N],map1[N][N],num,ans,n,a1[N],s,b[N],size[N];
bool stackf[N];
inline int min(int x,int y){return x<y?x:y;}
void tarjan(int u){
dfn[u]=++num;low[u]=num;stackf[u]=true;q.push(u);
for (int i=1;i<=n;++i){
if (map[u][i]){
if (!dfn[i]) tarjan(i),low[u]=min(low[u],low[i]);else if (stackf[i]) low[u]=min(low[u],dfn[i]);
}
}
if (dfn[u]==low[u]){
++s;int y;
do{
y=q.top();b[y]=s;size[s]++;stackf[y]=false;q.pop();
}while (y!=u);
}
}
int main(){
freopen("bzoj2208.in","r",stdin);
n=read();
for (int i=1;i<=n;++i) {
scanf("%s",s1+1);
for (int j=1;j<=n;++j) map[i][j]=s1[j]-'0';
}
for (int i=1;i<=n;++i) if (!dfn[i]) tarjan(i);
for (int i=1;i<=n;++i)
for (int j=1;j<=n;++j) {
if (map[i][j]&&b[i]!=b[j])
if (!map1[b[i]][b[j]]) map1[b[i]][b[j]]=1,f[b[i]][b[j]]=1,a1[b[j]]++;
}
for (int i=1;i<=s;++i) if (a1[i]==0) qq.push(i);num=0;
//for (int i=1;i<=s;++i) printf("%d ",a1[b[i]]);
while (!qq.empty()){
int x=qq.front();qq.pop();tp[++num]=x;
for (int i=1;i<=s;++i){
if (map1[x][i]) {
--a1[i];
if (!a1[i]) qq.push(i);
}
}
}
for (int i=1;i<=s;++i) f[i][i]=1;//printf("%d\n",size[i]);
for (int i=1;i<=s;++i) printf("%d ",tp[i]);
for (int i=s;i>=1;--i){
int x=tp[i];
for (int j=1;j<=s;++j) if (map1[x][j]) f[x]|=f[j];
}
for (int i=1;i<=s;++i)
for (int j=1;j<=s;++j)
if (f[i][j]) ans+=size[i]*size[j];
printf("%d",ans);
return 0;
}