[BZOJ2208][Jsoi2010]连通数

版权声明:辛辛苦苦码字,你们转载的时候记得告诉我 https://blog.csdn.net/dxyinme/article/details/83421676

Time Limit: 20 Sec
Memory Limit: 512 MB

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。

题解:
既然n<=2000那就n方算法干过去咯,tarjan缩环重建图,然后在DAG上跑dfs求每个点的联通数。刚好两次 n 2 n^2
///本来跟队友说我要练思维…结果脑子不行还是练手速来了。

#include<bits/stdc++.h>
#define LiangJiaJun main
#define ll long long
using namespace std;
struct edge{
    int to,nt;
}e[4000004];
int h[2004],n,m,ne;
char mp[2004][2004];
bool inq[2004],vis[2004];
int cnt,belong[2004],scc,low[2004],dfn[2004],sz[2004],ru[2004];
stack<int>st;
void add(int u,int v){
     e[++ne].to=v;e[ne].nt=h[u];
     h[u]=ne;
}
void dfs(int x){
     dfn[x]=low[x]=++cnt;
     inq[x]=1;
     st.push(x);
     for(int i=1;i<=n;i++){
         if(mp[x][i]=='0')continue;
         if(!dfn[i]){
            dfs(i);
            low[x]=min(low[x],low[i]);
         }
         else if(inq[i]){
            low[x]=min(low[x],dfn[i]);
         }
     }
     if(low[x]==dfn[x]){
        int now=-1;
        scc++;
        while(now!=x){
            now=st.top();st.pop();
            sz[scc]++;
            inq[now]=0;
            belong[now]=scc;
        }
     }
}
void rebuild(){
     for(int i=1;i<=n;i++){
         for(int j=1;j<=n;j++){
             if(mp[i][j]=='0')continue;
             if(belong[i]!=belong[j]){
                add(belong[i],belong[j]);
                ++ru[belong[j]];
             }
         }
     }
}
int f[2004];
int calc(int x){
    vis[x]=1;
    int res=0;
    for(int i=h[x];i;i=e[i].nt){
        if(!vis[e[i].to])res+=calc(e[i].to);
    }
    res+=sz[x];
    return res;
}

int w33ha(){
    scc=0;cnt=0;
    memset(ru,0,sizeof(ru));
    memset(belong,0,sizeof(belong));
    memset(low,0,sizeof(low));
    memset(dfn,0,sizeof(dfn));
    memset(sz,0,sizeof(sz));
    memset(f,0,sizeof(f));
    ne=0;
    memset(h,0,sizeof(h));
    for(int i=1;i<=n;i++)scanf("%s",mp[i]+1);
    for(int i=1;i<=n;i++){
        if(!dfn[i]){
            dfs(i);
        }
    }
    rebuild();
    ll ans=0;
    for(int i=1;i<=scc;i++){
        for(int j=1;j<=scc;j++)vis[j]=0;
        ans+=1LL*sz[i]*calc(i);
    }
    printf("%lld\n",ans);
    return 0;
}

int LiangJiaJun(){
    while(scanf("%d",&n)!=EOF)w33ha();
    return 0;
}

猜你喜欢

转载自blog.csdn.net/dxyinme/article/details/83421676