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,转载请注明来源
  • 相关阅读:
    Interview with BOA
    Java Main Differences between HashMap HashTable and ConcurrentHashMap
    Java Main Differences between Java and C++
    LeetCode 33. Search in Rotated Sorted Array
    LeetCode 154. Find Minimum in Rotated Sorted Array II
    LeetCode 153. Find Minimum in Rotated Sorted Array
    LeetCode 75. Sort Colors
    LeetCode 31. Next Permutation
    LeetCode 60. Permutation Sequence
    LeetCode 216. Combination Sum III
  • 原文地址:https://www.cnblogs.com/zhber/p/4216202.html
Copyright © 2011-2022 走看看