zhber
有好多做过的题没写下来,如果我还能记得就补吧

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。

 
原来我想的是用树形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;
}

  

posted on 2015-01-11 10:56  zhber  阅读(164)  评论(0编辑  收藏  举报