BZOJ2208连通数

还是挺简单的tarjan。

判断时可能重复,直接bitset搞定。

首先tarjan缩点,每个scc的内部肯定能互相到达,更一下,而且一个scc里的各个点的贡献肯定是一样的,topsort,更新答案就可以了,用bitset的count成上scc大小即可。

据说数据很水,大约O(n^3)可过,但是我看了看,没缩点,直接dfs,细节比较多,略烦,上述算法比较长,但是脑量比较小。还是比较好的,tarjan和topsort打得熟就15min搞定。

#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<cstdio>
#include<vector>
#include<queue>
#include<stack>
#include<bitset>
#include<map>
using namespace std;
struct EDGE{
    int ed,nex;
}edge[4000050],edgec[4000050];
int num,numc,ans,first[3000],firstc[3000];
int n,ord,sccnum,top;
int sta[1000000],dfn[3000],low[3000],bl[3000],du[3000];
char ch[3000];
bool ins[3000];
vector<int>scc[3000];
bitset<3000>s[3000];
void add(int st,int ed){
//    cout<<"st="<<st<<" ed="<<ed<<endl;
    edge[++num].ed=ed;
    edge[num].nex=first[st];
    first[st]=num;
}
void addc(int st,int ed){
//    cout<<"Stc="<<st<<" edc="<<ed<<endl;
    edgec[++numc].ed=ed;
    edgec[numc].nex=firstc[st];
    firstc[st]=numc;
}
void tarjan(int x){
    dfn[x]=low[x]=++ord;
    sta[++top]=x;ins[x]=1;
    for(int i=first[x];i;i=edge[i].nex){
        int y=edge[i].ed;
        if(!dfn[y]){
            tarjan(y);
            low[x]=min(low[x],low[y]);
        }else if(ins[y])
            low[x]=min(low[x],dfn[y]);
    }if(dfn[x]==low[x]){
        sccnum++;int p;
        do{
            p=sta[top--];ins[p]=0;
            bl[p]=sccnum;scc[sccnum].push_back(p);
        }while(p!=x);
    }
}
void topsort(){
    queue<int>q;
    for(int i=1;i<=sccnum;i++)
        if(du[i]==0) q.push(i);
    while(!q.empty()){
        int x=q.front();q.pop();
    //    cout<<x<<" ";
        for(int i=firstc[x];i;i=edgec[i].nex){
            int y=edgec[i].ed;
            du[y]--;
            s[y]|=s[x];
            if(du[y]==0)
                q.push(y);
        }
    }
}
int main(){
//    freopen("a,in","r",stdin);
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%s",ch+1);
        for(int j=1;j<=n;j++)
            if(ch[j]-'0')
                add(i,j);
    }
    for(int i=1;i<=n;i++)
        if(!dfn[i]) tarjan(i);
    for(int i=1;i<=n;i++)
        for(int j=first[i];j;j=edge[j].nex){
            int y=edge[j].ed;
            if(bl[i]==bl[y]) continue;
            addc(bl[i],bl[y]);
            du[bl[y]]++;
        }
    for(int i=1;i<=sccnum;i++){
        for(int j=0;j<scc[i].size();j++){
            int y=scc[i][j];
            s[i][y]=1;
        }        
    }
    topsort();
    for(int i=1;i<=sccnum;i++)
        ans+=s[i].count()*scc[i].size();
    printf("%d\n",ans);
    return 0;
}
View Code

猜你喜欢

转载自www.cnblogs.com/Yu-shi/p/11183135.html
今日推荐