您的位置:首页 > Web前端 > JavaScript

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

2017-10-30 11:10 357 查看

题目:

我是超链接

题解:

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

代码:

#include <cstdio>
#include <bitset>
#include <queue>
#include <cstring>
#include <iostream>
#define LL long long
#define N 2005
using namespace std;
bitset<2005>what
;
int tot,nxt[N*N],point
,v[N*N],tot1,nxt1[N*N],point1
,v1[N*N];
int dfn
,low
,stack
,cnt,num,nn,belong
,where
,in
,xl
;LL ans;
int x[N*N],y[N*N];
bool vis
;
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
;
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);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: