注意 tarjan 的功能
是求出 强联通量 进行缩点。
最终还需要求一下入度为零的超级点
#include<bits/stdc++.h>
using namespace std;
#define maxn 2005
#define inf 0x3f3f3f3f
int a[maxn];
vector<int>mmp[maxn];
int in[maxn],dfn[maxn],low[maxn],stk[maxn],instk[maxn];
int n,m,u,v,index,cnt,tot,color[maxn],cost[maxn],ans,sum;
void tarjan(int u)
{
int v;
low[u]=dfn[u]=++tot;
stk[++index]=u;
instk[u]=1;
for(int j=0; j<mmp[u].size(); j++)
{
v=mmp[u][j];
if(!dfn[v])
{
tarjan(v);
low[u]=min(low[v],low[u]);
}
else if(instk[v])//在栈内才有资格去更新
{
low[u]=min(low[u],dfn[v]);
}
}
if(low[u]==dfn[u])
{
++cnt;
do
{
v=stk[index--];
color[v]=cnt;
instk[v]=0;//出栈取消标记。
}
while(v!=u);
}
}
void solve()
{
memset(in,0,sizeof(in));
memset(dfn,0,sizeof(dfn));
memset(instk,0,sizeof(instk));
memset(color,0,sizeof(color));
memset(cost,inf,sizeof(cost));
memset(low,0,sizeof(low));
memset(stk,0,sizeof(stk));
cnt=tot=ans=sum=0;
index=-1;
for(int i=1; i<=n; i++)
if(!dfn[i])
tarjan(i);
for(int i=1; i<=n; i++)
cost[color[i]]=min(cost[color[i]],a[i]);
for(int i=1; i<=n; i++)
for(int j=0; j<mmp[i].size(); j++)
if(color[mmp[i][j]]!=color[i])
in[color[mmp[i][j]]]++;
for(int i=1; i<=cnt; i++)
if(in[i]==0)
{
ans+=cost[i];
sum++;
}
cout<<sum<<" "<<ans<<endl;
}
int main()
{
ios::sync_with_stdio(false);
while(cin>>n>>m)
{
for(int i=1; i<=n; i++)
{
cin>>a[i];
mmp[i].clear();
}
while(m--)
{
cin>>u>>v;
mmp[u].push_back(v);
}
solve();
}
return 0;
}
本文介绍了一个使用Tarjan算法求解强连通分量并进一步计算入度为零的超级节点的问题。通过递归的方式,利用低值和访问时间来判断强连通分量,并将这些分量缩点形成新的图,最后找出所有入度为零的超级节点。
4万+

被折叠的 条评论
为什么被折叠?



