bzoj 2208: [Jsoi2010]连通数
Posted yxysuanfa
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj 2208: [Jsoi2010]连通数相关的知识,希望对你有一定的参考价值。
2208: [Jsoi2010]连通数
Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 1682 Solved: 686
[Submit][Status][Discuss]
Description
Input
输入数据第一行是图顶点的数量,一个正整数N。 接下来N行,每行N个字符。第i行第j列的1表示顶点i到j有边,0则表示无边。
Output
输出一行一个整数,表示该图的连通数。
Sample Input
3
010
001
100
010
001
100
Sample Output
9
HINT
对于100%的数据。N不超过2000。
Source
思路:
连通性,强连通分量分解,然后依照拓扑排序dp,用bitset来实现dp过程
#include <iostream> #include <cstdio> #include <vector> #include <bitset> using namespace std; #define LL long long #define PB push_back const int N = 2005; vector<int> G[N], rG[N]; vector<int> vs; int belong[N]; bool used[N]; int V; void dfs(int u) { used[u] = 1; for(int i = 0; i < G[u].size(); ++i) { int v = G[u][i]; if(used[v] == 0) dfs(v); } vs.PB(u); } void rdfs(int u, int k) { used[u] = 1; belong[u] = k; for(int i = 0; i < rG[u].size(); ++i) { int v = rG[u][i]; if(used[v] == 0) rdfs(v, k); } } int scc() { fill(used, used + V, 0); vs.clear(); for(int i = 0; i < V; ++i) { if(used[i] == 0) dfs(i); } fill(used, used + V, 0); int k = 0; for(int i = vs.size() - 1; i >= 0; --i) { int u = vs[i]; if(used[u] == 0) rdfs(u, k++); } return k; } char str[N][N]; int cnt[N]; int fr[N * N], to[N * N], e_tot; vector<int> tG[N]; int du[N]; int que[N], f, t; bitset<N> dp[N]; int main() { int n; scanf("%d", &n); V = n; for(int i = 0; i < n; ++i) { scanf("%s", str[i]); } for(int i = 0; i < n; ++i) { for(int j = 0; j < n; ++j) { if(str[i][j] == ‘1‘) { if(i == j) continue; G[i].PB(j); rG[j].PB(i); fr[e_tot] = i; to[e_tot++] = j; } } } int scc_tot = scc(); for(int i = 0; i < V; ++i) { ++cnt[belong[i]]; } for(int i = 0; i < e_tot; ++i) { int v = belong[fr[i]]; int u = belong[to[i]]; if(u == v) continue; tG[u].PB(v); ++du[v]; } f = t = 0; for(int i = 0; i < scc_tot; ++i) { dp[i][i] = 1; if(du[i] == 0){ que[t++] = i; } } while(f != t) { int u = que[f++]; for(int i = 0; i < tG[u].size(); ++i) { int v = tG[u][i]; --du[v]; dp[v] |= dp[u]; if(du[v] == 0) que[t++] = v; } } //for(int i = 0; i < scc_tot; ++i) // cout<<dp[i]<<endl; LL ans = 0; for(int i = 0; i < scc_tot; ++i) { LL tmp = 0; for(int j = 0; j < scc_tot; ++j) { if(dp[i][j] == 1) { tmp += cnt[j]; } } ans += cnt[i] * tmp; } cout<<ans<<endl; return 0; }
以上是关于bzoj 2208: [Jsoi2010]连通数的主要内容,如果未能解决你的问题,请参考以下文章