[BZOJ2208][Jsoi2010]连通数(tarjan+topdp)

来源:互联网 发布:处理数据 英文 编辑:程序博客网 时间:2024/06/05 21:14

题目:

我是超链接

题解:

先缩点,然后倒着连边x->y表示y可以到达x的所有点,即“继承”x,最后就是有联系的集团个数相乘

代码:

#include <cstdio>#include <bitset>#include <queue>#include <cstring>#include <iostream>#define LL long long#define N 2005using namespace std;bitset<2005>what[N];int tot,nxt[N*N],point[N],v[N*N],tot1,nxt1[N*N],point1[N],v1[N*N];int dfn[N],low[N],stack[N],cnt,num,nn,belong[N],where[N],in[N],xl[N];LL ans;int x[N*N],y[N*N];bool vis[N];void addline(int x,int y){++tot; nxt[tot]=point[x]; point[x]=tot; v[tot]=y;}void addline1(int x,int y){++tot1; nxt1[tot1]=point1[x]; point1[x]=tot1; v1[tot1]=y;}void tarjan(int x){    dfn[x]=low[x]=++nn; vis[x]=1; stack[++cnt]=x;    for (int i=point[x];i;i=nxt[i])      if (!dfn[v[i]])      {        tarjan(v[i]);        low[x]=min(low[x],low[v[i]]);      }      else if (vis[v[i]]) low[x]=min(low[x],dfn[v[i]]);    if (low[x]==dfn[x])    {        num++;int now=0;        while (now!=x)        {            now=stack[cnt--];            vis[now]=0;            belong[num]++;            where[now]=num;        }    } }void top(){    queue<int>q;memset(vis,0,sizeof(vis));    int i,j=0;    for (i=1;i<=num;i++)       if (!in[i]) q.push(i);    while (!q.empty())    {        int now=q.front();q.pop();        xl[++j]=now; vis[now]=1;        for (int i=point1[now];i;i=nxt1[i])          if (!vis[v1[i]])          {            what[v1[i]]|=what[now];            in[v1[i]]--;             if (!in[v1[i]]) q.push(v1[i]);          }    }    }int main(){    int n,i,j,bian=0;char st[N];    scanf("%d",&n);    for (i=1;i<=n;i++)    {        scanf("%s",st+1);        for (j=1;j<=n;j++)            if (st[j]=='1')           {            x[++bian]=i;            y[bian]=j;            addline(i,j);          }    }    for (i=1;i<=n;i++)      if (!dfn[i]) tarjan(i);    for (i=1;i<=bian;i++)      if (where[x[i]]!=where[y[i]])        addline1(where[y[i]],where[x[i]]),in[where[x[i]]]++;     for (i=1;i<=num;i++) what[i][i]=1;          top();        for (i=1;i<=num;i++)      for (j=1;j<=num;j++)        if (what[i][j])          ans+=(LL)belong[i]*belong[j];    printf("%lld",ans);}
原创粉丝点击