zoukankan      html  css  js  c++  java
  • bzoj2208 [Jsoi2010]连通数

    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
    ",ans);
        return 0;
    }
    

      

    ——by zhber,转载请注明来源
  • 相关阅读:
    用户调查报告
    beta冲刺总结
    beta冲刺第七天
    beta冲刺第六天
    beta冲刺第五天
    beta冲刺第四天
    beta冲刺第三天
    beta冲刺第二天
    beta冲刺第一天
    简单的密码管理器(Python)(待完善)
  • 原文地址:https://www.cnblogs.com/zhber/p/4216202.html
Copyright © 2011-2022 走看看