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

    题目链接http://www.lydsy.com/JudgeOnline/problem.php?id=2208

    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。

    题解

    先tarjan缩点,然后对于两个连通的连通块,显然其对答案的贡献为sum[i]*sum[j],sum为块中节点个数

    代码

    #include<iostream>
    #include<cstdlib>
    #include<cstdio>
    #include<queue>
    #include<algorithm>
    #define N 2010
    using namespace std;
    int head[N],next[N*N],to[N*N];
    int Head[N],Next[N*N],To[N*N];
    int dfn[N],low[N],belong[N],c[N],s[N],num[N];
    int sum,p,q,g,top,n,f,ans;
    bool vis[N];
    char S[N];
    queue<int>Q;
    void link(int x,int y) {next[++sum]=head[x]; head[x]=sum; to[sum]=y;}
    void Link(int x,int y) {Next[++sum]=Head[x]; Head[x]=sum; To[sum]=y;}
    void tarjan(int p)
    {
        dfn[p]=low[p]=++sum; s[++top]=p; vis[p]=true;
        for (int i=head[p];i;i=next[i])
            {
                int v=to[i];
                if (!dfn[v]) {tarjan(v); low[p]=min(low[p],low[v]);}
                else if (vis[v]) low[p]=min(low[p],dfn[v]);
            }
        if (dfn[p]==low[p])
            {
                do
                    {
                        q=s[top--]; vis[q]=false;
                        belong[q]=p; num[p]++;
                    } while(p!=q);
                ans+=num[p]*num[p];
            }
    }
    void dfs(int p)
    {
        for (int j=Head[p];j;j=Next[j])
            if (!c[To[j]]) Q.push(To[j]),c[To[j]]=1,ans+=f*num[To[j]],dfs(To[j]);
    }
    int main()
    {
        freopen("1.in","r",stdin);
        freopen("1.out","w",stdout);
        scanf("%d",&n);
        for (int i=1;i<=n;i++)
            {
                scanf("%s",S);
                for (int j=0;j<=n-1;j++)
                    if (S[j]=='1') link(i,j+1);
            }
    
        sum=0;
        for (int i=1;i<=n;i++)
            if (!dfn[i]) tarjan(i);
    
        sum=0;
        for (int i=1;i<=n;i++)
            for (int j=head[i];j;j=next[j])
                if (belong[i]!=belong[to[j]]) Link(belong[i],belong[to[j]]);
    
        for (int i=1;i<=n;i++)
            if (belong[i]==i)
                {
                    while (!Q.empty()) {g=Q.front(); c[g]=0; Q.pop();}
                    f=num[i]; dfs(i);
                }
    
        printf("%d
    ",ans);
        return 0;
    }
    转载请联系博主!!!
  • 相关阅读:
    1112评论
    1029 C语言文法
    0909编译原理理解和解释
    复利计算4.0-单元测试
    命令解析程序的编写
    《构建之法》1、2、3章思考与感想
    复利计算4.0
    实验三的分析与总结
    复利计算(更新)
    单、复利计算程序
  • 原文地址:https://www.cnblogs.com/xiaoqiang200015/p/5970178.html
Copyright © 2011-2022 走看看