1 条题解
-
0

// SCC缩点+拓扑排序+bitset O(N) #include<bits/stdc++.h> using namespace std; const int N=2010; vector<int> e[N],ee[N]; int n,m,in[N],ans; int dfn[N],low[N],stk[N],top,scc[N],siz[N],cnt; bitset<N> f[N]; //f[i]表示i这个点的可以抵达点的数量,即二进制中1的个数 void tarjan(int x){ //SCC缩点 dfn[x]=low[x]=++dfn[0]; stk[++top]=x; for(auto y:e[x]){ if(!dfn[y]) tarjan(y),low[x]=min(low[x],low[y]); else if(!scc[y]) low[x]=min(low[x],dfn[y]); } if(dfn[x]==low[x]){ ++cnt; while(stk[top+1]!=x) scc[stk[top--]]=cnt,siz[cnt]++; } } void topo(){ queue<int> q; for(int i=1; i<=cnt; i++) if(!in[i]) q.push(i); while(!q.empty()){ int u=q.front(); q.pop(); f[u][u]=1; //可以到达自己 for(auto v:ee[u]){ f[v]|=f[u]; //非重复统计用并集运算 if(--in[v]==0) q.push(v); } } } int main(){ cin>>n; for(int i=1;i<=n;i++){ string s; cin>>s; for(int j=0;j<=s.size();j++) if(s[j]=='1') e[i].push_back(j+1); //连边 } for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i); //SCC缩点 for(int i=1;i<=n;i++)for(int j:e[i]) //枚举原始点的临接点 if(scc[j]!=scc[i]) ee[scc[j]].push_back(scc[i]),in[scc[i]]++; topo(); //对缩点拓扑DP for(int i=1;i<=cnt;i++)for(int j=1;j<=cnt;j++) //任意两个缩点(包括自身) if(f[i][j]) ans+=siz[i]*siz[j]; //如果可达,缩点之内的点必然可达 cout<<ans; }
- 1
信息
- ID
- 3873
- 时间
- 300ms
- 内存
- 128MiB
- 难度
- 10
- 标签
- 递交数
- 2
- 已通过
- 2
- 上传者