1. 程式人生 > >[BZOJ 2208] 連通數

[BZOJ 2208] 連通數

include 傳遞 spa back 排序 typedef names dag print

Link:

BZOJ 2208 連通數

Solution:

傳遞閉包模板題

傳遞閉包是集合中最小的二元關系,其實就是對二元關系的不斷拓展,一般用$floyd$求解

這裏要先跑一遍$tarjan$求出$SCC$,然後在$TopoSort$時順便傳遞閉包,最後統計答案即可

Tips:

1、在$DAG$上遞推使用拓撲排序更高效,直接$dfs$時間復雜度沒有保證,很可能$TLE$

2、如需對二進制位統一處理(位運算),使用$bitset$,能通過壓位快32倍

3、這題$O(n*m)$和$O(\frac{n^3}{32})$的純暴力都能過……

Code:

#include <bits/stdc++.h>

using
namespace std; typedef long long ll; const int MAXN=2005; ll res=0; bool vis[MAXN],instack[MAXN]; vector<int> G[MAXN];char dat[MAXN][MAXN]; int n,in[MAXN],low[MAXN],dfn[MAXN],col[MAXN],sum[MAXN],tp=0,cnt=0; stack<int> s; bitset<MAXN> f[MAXN]; void tarjan(int x) { dfn[x]=low[x]=++tp; vis[x]
=instack[x]=true; s.push(x); for(int i=0;i<G[x].size();i++) { int v=G[x][i]; if(instack[v]) low[x]=min(low[x],low[v]); else if(!vis[v]) tarjan(v),low[x]=min(low[x],low[v]); } if(low[x]==dfn[x]) { int tmp=-1;cnt++;
while(tmp!=x) { tmp=s.top();s.pop(); instack[tmp]=false; col[tmp]=cnt;sum[cnt]++; } } } void Topo_sort() { for(int i=1;i<=cnt;i++) f[i][i]=1; 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(); for(int i=0;i<G[u].size();i++) { int v=G[u][i];f[v]|=f[u]; if(!(--in[v])) q.push(v); } } } int main() { scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%s",dat[i]+1); for(int j=1;j<=n;j++) if(dat[i][j]==1) G[i].push_back(j); } for(int i=1;i<=n;i++) if(!vis[i]) tarjan(i); for(int i=0;i<MAXN;i++) G[i].clear(); for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) if(dat[i][j]==1 && col[i]!=col[j]) G[col[j]].push_back(col[i]),in[col[i]]++; Topo_sort(); for(int i=1;i<=cnt;i++) for(int j=1;j<=cnt;j++) if(f[i][j]) res+=1ll*sum[i]*sum[j]; printf("%lld",res); return 0; }

[BZOJ 2208] 連通數