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。
原来我想的是用树形dp搞,但是发现会重复统计
比如3个点3条边,1->2,2->3,1->3,先建反边按拓扑排序的顺序做:3更新1、2,但是2更新1的时候1已经统计过了3,所以重复记数
考虑状压一下,保存每个点能到达的点,更新的时候就不会重复统计了
说到状压,必须讲下bitset大法好!
当然缩点还是省不了的
#include<cstdio>
#include<iostream>
#include<bitset>
#define LL long long
#define N 2010
using namespace std;
inline LL read()
{
LL x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int n,cnt,cnt2,cnt3,tt,ans;
bitset <N> flag[N];
char ch[N];
struct edge{int to,next;}e[N*N],e2[N*N];
int head[N],head2[N],dfn[N],low[N];
int belong[N],size[N],son[N];
int zhan[N],top,q[N];
bool inset[N],mrk[N];
int I[N],O[N];
inline void insert(int u,int v)
{
e[++cnt].to=v;
e[cnt].next=head[u];
head[u]=cnt;
}
inline void ins(int u,int v)
{
e2[++cnt2].to=v;
e2[cnt2].next=head2[u];
head2[u]=cnt2;
}
inline void dfs(int x)
{
dfn[x]=low[x]=++tt;
zhan[++top]=x;inset[x]=1;
for (int i=head[x];i;i=e[i].next)
if (!dfn[e[i].to])
{
dfs(e[i].to);
low[x]=min(low[x],low[e[i].to]);
}else if (inset[e[i].to]) low[x]=min(low[x],dfn[e[i].to]);
if (dfn[x]==low[x])
{
int p=-1;
cnt3++;
while (p!=x)
{
p=zhan[top--];
belong[p]=cnt3;
inset[p]=0;
size[cnt3]++;
}
}
}
inline void tarjan()
{
for (int i=1;i<=n;i++)
if (!dfn[i])dfs(i);
}
int main()
{
n=read();
for (int i=1;i<=n;i++)
{
scanf("%s",ch+1);
for (int j=1;j<=n;j++)
if (ch[j]=='1')insert(i,j);
}
tarjan();
for (int i=1;i<=n;i++)
for (int j=head[i];j;j=e[j].next)
if (belong[e[j].to]!=belong[i])
{
ins(belong[e[j].to],belong[i]);
flag[belong[i]][belong[e[j].to]]=1;
I[belong[i]]++;
O[belong[belong[e[i].to]]]++;
}
int t=0,w=0;
for (int i=1;i<=cnt3;i++)
{
flag[i][i]=1;
if (!I[i])q[w++]=i,mrk[i]=1;
}
while (t!=w)
{
int now=q[t++];
for (int i=head2[now];i;i=e2[i].next)
{
int to=e2[i].to;
if (mrk[to])continue;
flag[to]|=flag[now];
I[to]--;
if (!I[to])
{
mrk[to]=1;
q[w++]=to;
}
}
}
for (int i=1;i<=cnt3;i++)
for (int j=1;j<=cnt3;j++)
if (flag[i][j])ans+=size[i]*size[j];
printf("%d\n",ans);
return 0;
}
——by zhber,转载请注明来源
浙公网安备 33010602011771号