E - Summer Holiday-联通量求入度

本文介绍了一个使用Tarjan算法求解强连通分量并进一步计算入度为零的超级节点的问题。通过递归的方式,利用低值和访问时间来判断强连通分量,并将这些分量缩点形成新的图,最后找出所有入度为零的超级节点。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

注意 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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值