bzoj 2208: [Jsoi2010]连通数 (dfs|tarjan+bitset+拓扑序)

来源:互联网 发布:超星网络选修课怎么刷 编辑:程序博客网 时间:2024/05/22 03:32

2208: [Jsoi2010]连通数

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

第一轮

[Submit][Status][Discuss]

题解:dfs

数据范围很小,直接暴力即可。

貌似正解是tarjan+拓扑序

#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>#include<cmath>#define N 5000003using namespace std;int n,m;int point[N],next[N],v[N],ans,vis[N],num,tot;char s[3003];void add(int x,int  y){tot++; next[tot]=point[x]; point[x]=tot; v[tot]=y;}void dfs(int now,int x){vis[x]=now; ans++;for (int i=point[x];i;i=next[i]) if (vis[v[i]]<now) dfs(now,v[i]);}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') add(i,j);}for (int i=1;i<=n;i++) dfs(i,i);printf("%d\n",ans);}

tarjan+bitset+拓扑序

tarjan缩点后,每次块内的点可以相互到达,ans+=num[i]*num[i],num[i]表示的是强连通块内点的个数。

然后考虑块与块之间的影响,按照拓扑序进行更新,然后用bitset记录块与块之间的到达关系,记录答案即可。

#include<iostream>#include<cstdio>#include<algorithm>#include<cstring>#include<cmath>#include<queue>#include<bitset>#define N 5000003#define M 2003using namespace std;int n,m,top;int point[M],next[N],v[N],vis[M],num[N],tot,cnt1,sum[N],ans,sz,map[M][M];int x[N],y[N],cnt,dfsn[M],st[N],belong[M],ins[M],low[M],outs[M];char s[3003];bitset<M> mark[M];void add(int x,int  y){tot++; next[tot]=point[x]; point[x]=tot; v[tot]=y;//cout<<x<<" "<<y<<endl;}void tarjan(int x){low[x]=dfsn[x]=++sz;ins[x]=1; st[++top]=x;for (int i=point[x];i;i=next[i]) { int j=v[i]; if (!dfsn[j]) tarjan(j),low[x]=min(low[x],low[j]); else if(ins[j]) low[x]=min(low[x],dfsn[j]); }if(low[x]==dfsn[x]) {++cnt;int j;do{j=st[top--]; num[cnt]++;belong[j]=cnt; ins[j]=0;}while(j!=x);sum[cnt]=num[cnt];ans+=num[cnt]*num[cnt];}}int main(){freopen("a.in","r",stdin);freopen("my.out","w",stdout);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') add(i,j),x[++cnt1]=i,y[cnt1]=j;}for (int i=1;i<=n;i++) if (!dfsn[i]) tarjan(i);tot=0;memset(point,0,sizeof(point));memset(next,0,sizeof(next));memset(ins,0,sizeof(ins));//cout<<endl;for (int i=1;i<=cnt1;i++) if (belong[x[i]]!=belong[y[i]]) {   int t=belong[x[i]]; int t1=belong[y[i]];   map[t][t1]=1; }for (int i=1;i<=cnt;i++) for (int j=1;j<=cnt;j++)  if (map[i][j]) add(i,j),ins[j]++,outs[i]++;queue<int> p; for (int i=1;i<=cnt;i++) if (!ins[i]) p.push(i);for (int i=1;i<=cnt;i++) mark[i][i]=1;while (!p.empty()) {int now=p.front(); p.pop();int t=0;for (int i=1;i<=cnt;i++) if(mark[now][i]&&i!=now) t+=num[i];ans+=t*num[now];for (int i=point[now];i;i=next[i]) { mark[v[i]]|=mark[now]; ins[v[i]]--; if (!ins[v[i]]) p.push(v[i]); }}printf("%d\n",ans);}


0 0
原创粉丝点击