
标签:

输入数据第一行是图顶点的数量,一个正整数N。 接下来N行,每行N个字符。第i行第j列的1表示顶点i到j有边,0则表示无边。
输出一行一个整数,表示该图的连通数。
对于100%的数据,N不超过2000。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<string>
#include<algorithm>
#include<bitset>
#include<queue>
#include<vector>
#include<stack>
using namespace std;
vector<int> e[2005],g[2005];
stack<int> s;
bitset<2005> f[2005];
int n,mp[2005][2005];
int Dfs[2005],low[2005],use[2005],top,newflag,isstack[2005],in[2005],num[2005];
bool vis[2005][2005];
void tarjan(int u)
{
Dfs[u]=low[u]=++top;
isstack[u]=1;
s.push(u);
for(int i=0;i<e[u].size();i++)
{
int v=e[u][i];
if(!Dfs[v])
{
tarjan(v);
low[u]=min(low[u],low[v]);
}
else if(isstack[v])
low[u]=min(low[u],Dfs[v]);
}
if(low[u]==Dfs[u])
{
newflag++;
int x;
do
{
x=s.top();
s.pop();
isstack[x]=0;
use[x]=newflag;
num[newflag]++;
}while(x!=u);
}
}
void topsort()
{
queue<int> q;
for(int i=1;i<=newflag;i++)
{
f[i][i]=1;
if(in[i]==0)
q.push(i);
}
while(!q.empty())
{
int x=q.front();
q.pop();
for(int i=0;i<g[x].size();i++)
{
int v=g[x][i];
f[v]=f[v]|f[x];
if(--in[v]==0)
q.push(v);
}
}
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
scanf("%1d",&mp[i][j]);
if(i!=j&&mp[i][j])
e[i].push_back(j);
}
}
for(int i=1;i<=n;i++)
{
if(!Dfs[i])
tarjan(i);
}
for(int i=1;i<=n;i++)
{
for(int j=0;j<e[i].size();j++)
{
int u,v;
u=i,v=e[i][j];
if(use[u]!=use[v]&&!vis[use[u]][use[v]])
{
g[use[u]].push_back(use[v]);
vis[use[u]][use[v]]=1;
in[use[v]]++;
}
}
}
topsort();
int ans=0;
for(int i=1;i<=newflag;i++)
{
for(int j=1;j<=newflag;j++)
{
if(f[i][j])
ans+=num[i]*num[j];
}
}
printf("%d\n",ans);
return 0;
}
(tarjan建图+topsort+状态压缩) bzoj 2208
标签:
原文地址:http://www.cnblogs.com/water-full/p/4516235.html