E - Summer Holiday-联通量求入度

注意 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;
}

猜你喜欢

转载自blog.csdn.net/BePosit/article/details/81590301
今日推荐