Tarjan(强连通分量缩点) - Mouse Hunt - CodeForces 1027D

Tarjan(强连通分量缩点) - Mouse Hunt - CodeForces 1027D

题意:

n n 给定一个n个点,n条边的有向图,

初始时,老鼠可能在任意点,

i a i 接着老鼠将从点i到点a_i,

i c i 在i点放置一个捕捉装置需要花费c_i,

( ) 计算最少花费,能够确保抓住老鼠(无论老鼠从什么位置出发)。

输入:

n 首行一个正整数n,

n c 1 , c 2 , . . . , c n 接着n个正整数,c_1,c_2,...,c_n

n a 1 , a 2 , . . . , a n 最后一行为n个正整数:a_1,a_2,...,a_n

输出:

一个正整数,表示最少花费。

Examples
Input

5
1 2 3 2 10
1 3 4 3 3

Output

3

Input

4
1 10 2 10
2 4 2 2

Output

10

Input

7
1 1 1 1 1 1 1
2 2 2 3 6 7 6

Output

2

数据范围:

1 n 2 1 0 5 1 c i 1 0 4 1 a i n 1≤n≤2⋅10^5,1≤c_i≤10^4,1≤a_i≤n


分析:

i a i 根据题意,我们在i和a_i之间连接一条有向边,每个点有且仅有一条出边。

0 要能确保抓住老鼠,事实上,我们没有必要在入度为0的点上放置捕捉装置,

因为该点必然会到达其他点,我们在其能够到达的其他点上放捕捉装置也是可行的。

0 而且,我们必须在出度为0的点上放置一个捕捉装置。

t a r j a n 首先我们通过tarjan算法对强连通分量进行缩点,

每个强连通分量的权值为该强连通分量内部所有点的权值的最小值。

接着统计每一个连通分量的出度,

0 最后,我们将所有出度为0的点的权值累加上就是最小花费。

i = a i 注意,自环的情况需要特判,即i=a_i的情况,需要在该点上也放置一个装置。

代码:

#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
#include<algorithm>

#define ll long long

using namespace std;

const int N=200010, M=200010;

int n,m;
int e[M],ne[M],h[N],w[N],idx;
int stk[N],top;
bool in_stk[N];
int id[N],ssc_cnt;
int dfn[N],low[N],timestamp;
int minp[N],dout[N];
int a[N];

void add(int a,int b)
{
    e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}

void tarjan(int u)
{
    dfn[u]=low[u]=++timestamp;
    stk[++top]=u,in_stk[u]=true;
    for(int i=h[u];~i;i=ne[i])
    {
        int j=e[i];
        if(!dfn[j])
        {
            tarjan(j);
            low[u]=min(low[u],low[j]);
        }
        else if(in_stk[j]) low[u]=min(low[u],dfn[j]);
    }

    if(dfn[u]==low[u])
    {
        ++ssc_cnt;
        int y;
        do
        {
            y=stk[top--];
            in_stk[y]=false;
            id[y]=ssc_cnt;
            minp[ssc_cnt]=min(minp[ssc_cnt],w[y]);
        }while(y!=u);
    }
}

int main()
{
    cin>>n;
    for(int i=1;i<=n;i++) scanf("%d",&w[i]);
    memset(h,-1,sizeof h);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
        add(i,a[i]);
    }
    
    memset(minp,0x3f,sizeof minp);
    for(int i=1;i<=n;i++)
        if(!dfn[i])
            tarjan(i);
        
    for(int i=1;i<=n;i++)
        for(int j=h[i];~j;j=ne[j])
        {
            int k=e[j];
            int u=id[i], v=id[k];
            if(a[i]==i || u==v) continue;
            dout[u]++;
        }

    int res=0;
    for(int i=1;i<=ssc_cnt;i++)
        if(!dout[i])
            res+=minp[i];

    cout<<res<<endl;
    
    return 0;
}

猜你喜欢

转载自blog.csdn.net/njuptACMcxk/article/details/107719356