题目描述
度量一个有向图恋情情况的一个指标是连通,指途中可达点对的个数。
下图的连通数是14
现在要你求出连通数
输入格式:
输入数据第一行是图顶点的数量,一个正整数 N N N。 接下来 N N N行,每行 N N N个字符。第 i i i行第 j j j 列的 1 1 1表示顶点 i i i到 j j j有边, 0 0 0则表示无边。
输出格式:
输出一行一个整数,表示该图的连通数。
输入样例#1:
3
010
001
100
输出样例#1:
9
输入样例#2:
5
01100
00101
00011
00000
00000
输入样例#2:
14
思路
这个图让我们求联通数,一个点如果能到达另一个点,这说明这两个点联通(包括同一个点)。 因为一个环内的点一定可以互相到达,所以我们考虑Tarjan缩点。
缩完点之后图变成了一个DAG(有向无环图)。我们就可以 O ( n 2 ) O(n^2) O(n2) 来统计答案。
我们枚举起点,然后从起点开始遍历。这样找到的点对一定是不重复的(因为起点不同)。 设缩完点后点的大小为
s
z
[
i
]
sz[i]
sz[i],从这个点往下可以走到的点数为
n
u
b
[
i
]
nub[i]
nub[i]。
则这个点对答案的贡献为
s
z
[
i
]
∗
s
z
[
i
]
+
s
z
[
i
]
∗
n
u
b
[
i
]
sz[i] *sz[i] + sz[i] *nub[i]
sz[i]∗sz[i]+sz[i]∗nub[i]
code
#include<bits/stdc++.h>
using namespace std;
const int maxn = 2333;
struct node
{
int f , t;
}e[maxn * maxn];
int n , m , tot , cnt , num , ks;
int head[maxn] , nxt[maxn * maxn] , low[maxn] , dfn[maxn] , w[maxn];
int used[maxn] , x[maxn * maxn] , y[maxn * maxn] , nub[maxn];
int sta[maxn] , stc , col[maxn] , ans;
char k[maxn][maxn];
inline void build(int a , int b)
{
e[++tot] = (node){a ,b};
nxt[tot] = head[a];
head[a] = tot;
}
inline int read()
{
int x = 0, f = 1;
char ch = getchar();
while (ch < '0' || ch > '9') { if (ch == '-') f = -1; ch = getchar(); }
while (ch >= '0' && ch <= '9') { x = x * 10 + ch - 48; ch = getchar(); }
return x * f;
}
inline void tarjan(int b)
{
low[b] = dfn[b] = ++cnt;
sta[++stc] = b;
used[b] = 1;
for(int i = head[b] ; i ; i = nxt[i])
{
int u = e[i].t;
if(!dfn[u])
{
tarjan(u);
low[b] = min(low[b] , low[u]);
}
else if(used[u])
low[b] = min(low[b] , dfn[u]);
}
if(low[b] == dfn[b])
{
num ++;
while(b != sta[stc + 1])
{
used[sta[stc]] = 0;
col[sta[stc]] = num;
stc--;
}
}
}
inline void rebuild()
{
for(int i = 1 ; i <= tot ; i ++)
{
e[i].f = 0;
e[i].f = 0;
}tot = 0;
memset(head , 0 , sizeof(head));
memset(nxt , 0 , sizeof(nxt));
memset(used , 0 , sizeof(used));
for(int i = 1 ; i <= m ; i ++)
if(col[x[i]] != col[y[i]])
build(col[x[i]] , col[y[i]]);
}
inline void ser(int x)
{
ks += nub[x];
for(int i = head[x] ; i ; i = nxt[i])
{
int u = e[i].t;
if(!used[u])
{
used[u] = 1;
ser(u);
}
}
}
int main()
{
// freopen("s.in","r",stdin);
n = read();
for(int i = 1 ; i <= n ; i ++)
for(int j = 1 ; j <= n ; j ++)
{
char k;
cin>>k;
if(k == '1')
{
x[++m] = i , y[m] = j;
build(i , j);
}
}
for(int i = 1 ; i <= n ;i ++)
if(!dfn[i]) tarjan(i);
rebuild();
for(int i = 1 ; i <= n ; i ++) nub[col[i]] ++;
for(int i = 1 ; i <= num ; i ++)
{
for(int j = 1 ; j <= num ; j ++ ) used[j] = 0;
ks = 0;
used[i] = 1;
ser(i);
// cout<<ks - nub[i]<<" ";
ans += nub[i] * (ks - nub[i]);
ans += nub[i] * nub[i];
}
// cout<<num;
// for(int i = 1 ; i <= num ; i ++) cout<<nub[i]<<" ";
cout<<ans;
}
End