BZOJ 2208 [Jsoi2010]连通数 - Tarjan_SCC/Floyd+bitset优化
2017-09-13 23:01
501 查看
首先进行Tarjan缩点,将自环缩成一个点,已知自环中点相互连通,现在只需求环与环之间的联通情况。这里需要反向建图,利用从子节点更新父节点的思想,把to的点信息传给from。最后是一个乘法原理,讨论每一对环的关系,若之间有连通,则两个环中每一个点都能够相连,因此相乘。而对于自环中的连通也可以一并由其bccnum的平方算出。
下面是一种[b]bitset优化的Floyd传递闭包的方法,其复杂度为O(n^2)
注意和朴素的floyd方法相似,先枚举中间点,只不过这里的后继点利用bitset二进制状态表示。
#include<iostream> #include<cstring> #include<cstdio> #include<cstdlib> #include<bitset> #include<queue> #include<algorithm> using namespace std; const int maxn=2005; struct edge { int next,to; }e[maxn*maxn],e_[maxn*maxn]; int n; int head[maxn],head_[maxn],in[maxn]; int dfn[maxn],low[maxn],stack[maxn],belong[maxn]; bool is_in[maxn]; int top,dfs_clock,bcccnt,bccnum[maxn]; bitset<maxn>dist[maxn]; void insert(int a,int b) { static int cnt=0; e[++cnt].to=b;e[cnt].next=head[a];head[a]=cnt; } void insert_(int a,int b) { static int cnt=0; e_[++cnt].to=b;e_[cnt].next=head_[a];head_[a]=cnt;in++; } void tarjan(int x) { dfn[x]=low[x]=++dfs_clock; stack[++top]=x; is_in[x]=true; for(int i=head[x];i;i=e[i].next) { int y=e[i].to; if(!dfn[y]) tarjan(y),low[x]=min(low[x],low[y]); else if(is_in[y]) low[x]=min(low[x],dfn[y]); } if(dfn[x]==low[x]) { ++bcccnt; int now=-1; while(now!=x) { now=stack[top--]; belong[now]=bcccnt; is_in[now]=false; bccnum[bcccnt]++; } } } void rebuild() { for(int i=1;i<=n;i++) for(int j=head[i];j;j=e[j].next) if(belong[i]!=belong[e[j].to]) insert_(belong[i],belong[e[j].to]);//反向建边 } void topological_sort() { queue<int>q; for(int i=1;i<=n;i++)dist[i][i]=true; for(int i=1;i<=n;i++) if(!in[i])q.push(i); while(!q.empty()) { int u=q.front(); q.pop(); for(int i=head_[u];i;i=e_[i].next) { int v=e_[i].to; in[v]--; dist[v]|=dist[u]; if(!in[v])q.push(v); } } } int main() { scanf("%d",&n); char s[maxn]; for(int i=1;i<=n;i++) { scanf("%s",s+1); for(int j=1;j<=n;j++) if(s[j]=='1')insert(i,j); } for(int i=1;i<=n;i++) if(!dfn[i])tarjan(i); rebuild(); topological_sort(); int ans=0; for(int i=1;i<=bcccnt;i++) for(int j=1;j<=bcccnt;j++) if(dist[i][j])ans+=bccnum[i]*bccnum[j]; printf("%d",ans); return 0; }
下面是一种[b]bitset优化的Floyd传递闭包的方法,其复杂度为O(n^2)
注意和朴素的floyd方法相似,先枚举中间点,只不过这里的后继点利用bitset二进制状态表示。
#include<iostream> #include<cstring> #include<cstdlib> #include<cstdio> #include<bitset> #include<algorithm> using namespace std; const int maxn=2005; int n; bitset<maxn>dist[maxn]; char s[maxn]; void floyd() { for(int j=1;j<=n;j++) for(int i=1;i<=n;i++) if(dist[i][j]) dist[i]|=dist[j]; } int main() { scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%s",s+1); for(int j=1;j<=n;j++) if(s[j]=='1'||i==j) dist[i][j]=true; } floyd(); int ans=0; for(int i=1;i<=n;i++) ans+=dist[i].count(); printf("%d",ans); return 0; }
相关文章推荐
- BZOJ 2208 JSOI 2010 连通数 Tarjan+bitset
- [tarjan+bitset]BZOJ 2208——[Jsoi2010]连通数
- BZOJ 2208 [Jsoi2010]连通数 tarjan缩点+bitset优化DP
- bzoj 2208: [Jsoi2010]连通数【tarjan+拓扑+dp】
- [BZOJ2208][Jsoi2010]连通数(dfs||tarjan+拓扑序+dp)
- BZOJ.2208.[JSOI2010]连通数(bitset Tarjan 拓扑)
- [BZOJ2208][Jsoi2010]连通数(tarjan+topdp)
- BZOJ 2208: [Jsoi2010]连通数 tarjan bitset
- BZOJ 2208 JSOI2010 连通数 Tarjan+拓扑排序
- bzoj 2208: [Jsoi2010]连通数 (dfs|tarjan+bitset+拓扑序)
- BZOJ 2208 JSOI2010 连通数 Tarjan+拓扑排序
- Dfs【p4306(bzoj 2208)】 [JSOI2010]连通数
- 【BZOJ2208】【JSOI2010】连通数 传递闭包
- BZOJ2208 [JSOI2010] 连通数
- 【bzoj2208】[Jsoi2010]连通数
- bzoj 2208: [Jsoi2010]连通数
- 【BZOJ】2208 [Jsoi2010]连通数
- 2208: [Jsoi2010]连通数 - BZOJ
- bzoj2208 [Jsoi2010]连通数(scc+bitset)
- bzoj2208 [Jsoi2010]连通数(tarjan缩点+拓扑排序+bitset传递闭包)