2208: [Jsoi2010]连通数
Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 2365 Solved: 1001
[ Submit][ Status][ Discuss]
Description
Input
输入数据第一行是图顶点的数量,一个正整数N。 接下来N行,每行N个字符。第i行第j列的1表示顶点i到j有边,0则表示无边。
Output
输出一行一个整数,表示该图的连通数。
Sample Input
3
010
001
100
010
001
100
Sample Output
9
HINT
对于100%的数据,N不超过2000。
Source
题解:dfs
数据范围很小,直接暴力即可。
貌似正解是tarjan+拓扑序
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define N 5000003
using 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 2003
using 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);
}