(tarjan建图+topsort+状态压缩) bzoj 2208

2208: [Jsoi2010]连通数

Time Limit: 20 Sec  Memory Limit: 512 MB
Submit: 1489  Solved: 606
[Submit][Status][Discuss]

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。

 

Source

 
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<string>
#include<algorithm>
#include<bitset>
#include<queue>
#include<vector>
#include<stack>
using namespace std;
vector<int> e[2005],g[2005];
stack<int> s;
bitset<2005> f[2005];
int n,mp[2005][2005];
int Dfs[2005],low[2005],use[2005],top,newflag,isstack[2005],in[2005],num[2005];
bool vis[2005][2005];
void tarjan(int u)
{
    Dfs[u]=low[u]=++top;
    isstack[u]=1;
    s.push(u);
    for(int i=0;i<e[u].size();i++)
    {
        int v=e[u][i];
        if(!Dfs[v])
        {
            tarjan(v);
            low[u]=min(low[u],low[v]);
        }
        else if(isstack[v])
            low[u]=min(low[u],Dfs[v]);
    }
    if(low[u]==Dfs[u])
    {
        newflag++;
        int x;
        do
        {
            x=s.top();
            s.pop();
            isstack[x]=0;
            use[x]=newflag;
            num[newflag]++;
        }while(x!=u);
    }
}
void topsort()
{
    queue<int> q;
    for(int i=1;i<=newflag;i++)
    {
        f[i][i]=1;
        if(in[i]==0)
            q.push(i);
    }
    while(!q.empty())
    {
        int x=q.front();
        q.pop();
        for(int i=0;i<g[x].size();i++)
        {
            int v=g[x][i];
            f[v]=f[v]|f[x];
            if(--in[v]==0)
                q.push(v);
        }
    }
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            scanf("%1d",&mp[i][j]);
            if(i!=j&&mp[i][j])
                e[i].push_back(j);
        }
    }
    for(int i=1;i<=n;i++)
    {
        if(!Dfs[i])
            tarjan(i);
    }
    for(int i=1;i<=n;i++)
    {
        for(int j=0;j<e[i].size();j++)
        {
            int u,v;
            u=i,v=e[i][j];
            if(use[u]!=use[v]&&!vis[use[u]][use[v]])
            {
                g[use[u]].push_back(use[v]);
                vis[use[u]][use[v]]=1;
                in[use[v]]++;
            }
        }
    }
    topsort();
    int ans=0;
    for(int i=1;i<=newflag;i++)
    {
        for(int j=1;j<=newflag;j++)
        {
            if(f[i][j])
                ans+=num[i]*num[j];
        }
    }
    printf("%d\n",ans);
    return 0;
}

  

posted @ 2015-05-20 08:37  waterfull  阅读(227)  评论(0编辑  收藏  举报