2208: [Jsoi2010]连通数

来源:互联网 发布:阿里云账号不记得了 编辑:程序博客网 时间:2024/06/05 07:15

2208: [Jsoi2010]连通数

Time Limit: 20 Sec  Memory Limit: 512 MB
Submit: 2403  Solved: 1021
[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

第一轮

[Submit][Status][Discuss]

边数是O(n^2)的,不可能每个点都BFS一遍
不过可以对原图缩点,这样剩下一个DAG,谁能走到谁就一目了然了
此时可以BFS一遍求出每个点可以到达的集合
这个地方集合是并操作所以不能累加。。(傻逼了),图方便直接上了个bitset
然后tarjan缩点的时候注意dfs最外层要一个for,而且反向边更新的前提是其指向点还没判进任何一个scc
tarjan懵逼ing。。。希望考场不要这么傻
#include<iostream>#include<cstdio>#include<algorithm>#include<cmath>#include<cstring>#include<vector>#include<queue>#include<set>#include<map>#include<stack>#include<bitset>#include<ext/pb_ds/priority_queue.hpp>using namespace std;const int maxn = 2020;int n,ans,scc,dfs_clock,dfn[maxn],low[maxn],bel[maxn],du[maxn],siz[maxn];char ch[maxn];vector <int> v[maxn];vector <int> v2[maxn];queue <int> Q;stack <int> s;bitset <maxn> B[maxn];void Dfs(int x){dfn[x] = low[x] = ++dfs_clock; s.push(x);for (int i = 0; i < v[x].size(); i++){int to = v[x][i];if (!dfn[to]) Dfs(to),low[x] = min(low[x],low[to]);else if (!bel[to]) low[x] = min(low[x],dfn[to]);}if (low[x] == dfn[x]){++scc;for (;;){int tp = s.top(); s.pop();bel[tp] = scc; ++siz[scc];B[scc][tp] = 1;if (tp == x) break;}}}int main(){#ifdef DMCfreopen("DMC.txt","r",stdin);#endifcin >> n;for (int i = 1; i <= n; i++){scanf("%s",ch + 1);for (int j = 1; j <= n; j++)if (ch[j] == '1') v[i].push_back(j);}for (int i = 1; i <= n; i++)if (!dfn[i]) Dfs(i);for (int i = 1; i <= n; i++)for (int j = 0; j < v[i].size(); j++){int x = bel[i],y = bel[v[i][j]];if (x == y) continue;++du[x]; v2[y].push_back(x);}for (int i = 1; i <= scc; i++)if (!du[i]) Q.push(i);while (!Q.empty()){int k = Q.front(); Q.pop();ans += siz[k]*B[k].count();for (int i = 0; i < v2[k].size(); i++){int to = v2[k][i]; --du[to];B[to] |= B[k];if (!du[to]) Q.push(to);}}cout << ans;return 0;}

0 0
原创粉丝点击