bzoj 2208: [Jsoi2010]连通数 拓扑排序+强连通分量+bitset

来源:互联网 发布:赣州四中官网网络阅卷 编辑:程序博客网 时间:2024/05/17 02:03

题意

给出一个有向图,求有多少个点对(i,j)满足i可以到达j(i可以等于j)

分析

这题据说暴力也能卡过去,毕竟20s的时限我才跑了1s+,但打暴力的话就没意思了,所以就果断码了一波正解。
这题一开始也有一点大概的思路也就是用bitset之类的状态压缩来搞一搞,但是没想到用tarjan来缩点。
那么正解其实就是先用tarjan来缩一下点,那么每个强连通分量对ans的贡献就是size*size,然后拓扑排序一下,再用bitset来记录每个点能到达那些点就好了。

总结

以后碰到求有向图无向图求连通数的时候要记得用tarjan缩点。
第一次用bitset

代码

#include<iostream>#include<cstdio>#include<cstdlib>#include<cstring>#include<algorithm>#include<bitset>#include<stack>#define N 2005using namespace std;bitset <N> vis[N];stack <int> q;int low[N],dfn[N],bel[N],size[N],map[N][N],map1[N][N],n,tot,sum,ans,du[N],f[N];char str[N];void tarjan(int x){    dfn[x]=++tot;    low[x]=tot;    q.push(x);    f[x]=1;    for (int i=1;i<=n;i++)        if (map[x][i]&&!dfn[i])        {            tarjan(i);            low[x]=min(low[x],low[i]);        }        else if (map[x][i]&&f[i]) low[x]=min(low[x],low[i]);    if (low[x]==dfn[x])    {        sum++;        while (1)        {            int j=q.top();            q.pop();            f[j]=0;            bel[j]=sum;            size[sum]++;            vis[sum][j]=true;            if (j==x) break;        }        ans+=size[sum]*size[sum];    }}stack <int> q1;void topsort(){    while (!q.empty()) q.pop();    for (int i=1;i<=sum;i++)        if (!du[i])        {            q.push(i);            q1.push(i);        }    while (!q1.empty())    {        int x=q1.top();        q1.pop();        for (int i=1;i<=sum;i++)            if (map1[x][i])            {                du[i]--;                if (!du[i])                {                    q.push(i);                    q1.push(i);                }            }    }}int main(){    scanf("%d",&n);    for (int i=1;i<=n;i++)    {        scanf("%s",str);        for (int j=0;j<n;j++)            if (str[j]=='1') map[i][j+1]=1;    }    for (int i=1;i<=n;i++)        if (!dfn[i]) tarjan(i);    for (int i=1;i<=n;i++)        for (int j=1;j<=n;j++)            if (map[i][j]&&!map1[bel[i]][bel[j]]&&bel[i]!=bel[j])            {                map1[bel[i]][bel[j]]=1;                du[bel[j]]++;            }    topsort();    while (!q.empty())    {        int x=q.top();        q.pop();        bitset <N> t;        for (int i=1;i<=sum;i++)            if (map1[x][i]) t|=vis[i];        ans+=t.count()*size[x];        vis[x]|=t;    }    printf("%d",ans);    return 0;}
0 0
原创粉丝点击