您的位置:首页 > Web前端 > JavaScript

bzoj2208 [Jsoi2010]连通数(scc+bitset)

2015-12-18 15:28 696 查看

2208: [Jsoi2010]连通数

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

第一轮

【思路】

强连通分量+bitset传递闭包。

求出scc,缩点。对于新的DAG,如果两个scc之间相连则ans+=sccsz[i]*sccsz[j]。利用bitset与递推判断相连。

【代码】

#include<cstdio>
#include<bitset>
#include<queue>
#include<stack>
#include<vector>
#include<cstring>
#include<iostream>
using namespace std;

const int maxn = 2000+10;

int pre[maxn],lowlink[maxn],sccno[maxn],sccsz[maxn],dfs_clock,scc_cnt;
vector<int> G[maxn];
stack<int> S;

int dfs(int u) {
pre[u]=lowlink[u]=++dfs_clock;
S.push(u);
for(int i=0;i<G[u].size();i++) {
int v=G[u][i];
if(!pre[v]) {
dfs(v);
lowlink[u]=min(lowlink[u],lowlink[v]);
}
else if(!sccno[v]) {
lowlink[u]=min(lowlink[u],pre[v]);
}
}
if(lowlink[u]==pre[u]) {
scc_cnt++;
for(;;) {
int x=S.top(); S.pop();
sccno[x]=scc_cnt;
sccsz[scc_cnt]++;
if(x==u) break;
}
}
}
void find_scc(int n) {
memset(pre,0,sizeof(pre));
memset(sccsz,0,sizeof(sccsz));
memset(sccno,0,sizeof(sccno));
scc_cnt=dfs_clock=0;
for(int i=0;i<n;i++)
if(!pre[i]) dfs(i);
}

bitset<maxn> f[maxn];    //使用bitset
int n,in[maxn];
char s[maxn];

vector<int> Gx[maxn];
void rebuild() {
for(int i=1;i<=scc_cnt;i++) in[i]=0;
for(int i=0;i<n;i++) {
int u=sccno[i];
for(int j=0;j<G[i].size();j++) {
int v=sccno[G[i][j]];
if(u!=v) Gx[u].push_back(v),in[v]++;
}
}
}

queue<int> q;
void solve() {
for(int i=1;i<=scc_cnt;i++) f[i][i]=1;
for(int i=1;i<=scc_cnt;i++) if(!in[i]) q.push(i);
while(!q.empty()) {
int u=q.front(); q.pop();
for(int i=0;i<Gx[u].size();i++) {
int v=Gx[u][i];
f[v]|=f[u];            //传递闭包
if((--in[v])==0)  q.push(v);
}
}
}

int main() {
scanf("%d",&n);
for(int i=0;i<n;i++){
scanf("%s",s);
for(int j=0;j<n;j++) {
if(s[j]-'0') G[i].push_back(j);
}
}
find_scc(n);
rebuild();
solve();
int ans=0;
for(int i=1;i<=scc_cnt;i++)
{
for(int j=1;j<=scc_cnt;j++)
if(f[i][j]) ans+=sccsz[i]*sccsz[j];
}
printf("%d\n",ans);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: