Tarjan(强连通分量) - Checkposts - CodeForces 427C

Tarjan(强连通分量) - Checkposts - CodeForces 427C

题意:

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

i w i 现在要在某些点上设置警察局,在i点设置警察局的代价为w_i,

i j i j ( i j j i ) i点的警察局能够保护j点,当且仅当i和j之间能够双向到达(i能到j,j也能到i)。

使 1 0 9 + 7 现在要计算最少花费,使得所有的点都能够被警察局保护到。并计算最少花费的不同方案总数,结果对10^9+7取模。

当两个方案中存在一个警察局设置的位置不同,两个方案被认为是不同的

输入:

n 首行一个正整数n,

n w 1 , w 2 , . . . , w n 接着一行n个整数,w_1,w_2,...,w_n。

m 然后输入正整数m,

m m u i , v i u i v i 最后m行表示m条边,每行两个正整数u_i,v_i,表示点u_i和v_i之间有一条有向边。

输出:

两个正整数,分别表示最小花费和最小花费的不同方案总数。

Examples
Input

3
1 2 3
3
1 2
2 3
3 2

Output

3 1

Input

5
2 8 0 6 0
6
1 4
1 3
2 4
3 4
4 5
5 1

Output

8 2

Input

10
1 3 2 2 1 3 1 4 10 10
12
1 2
2 3
3 1
3 4
4 5
5 6
5 7
6 4
7 3
8 9
9 10
10 9

Output

15 6

Input

2
7 91
2
1 2
2 1

Output

7 1

数据范围:

1 n 1 0 5 0 m 3 1 0 5 0 w i 1 0 9 1 u i , v i n ; u v 1 ≤ n ≤ 10^5,0 ≤ m ≤ 3·10^5,0≤w_i≤10^9,1 ≤ u_i, v_i ≤ n; u ≠ v


分析:

使 使 由题意,要使得总花费最小,就要使得每个强连通分量的化费最小。

t a r j a n m i n p c n t _ m i n p 首先通过tarjan算法求强连通分量,同时维护两个数组minp和cnt\_minp,

分别表示每个强连通块内部所有点中的最小点权,和最小点权的数量。

i = 1 s s c _ c n t m i n p [ i ] s s c _ c n t 则总的最少花费为:\sum_{i=1}^{ssc\_cnt}minp[i],其中ssc\_cnt表示强连通块的数量。

i = 1 s s c _ c n t c n t _ m i n p [ i ] 根据乘法原理,最少花费的不同方案总数为:\prod_{i=1}^{ssc\_cnt}cnt\_minp[i]。

代码:

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

#define ll long long

using namespace std;

const int N=100010, M=300010, mod=1e9+7;

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],cnt_minp[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;
            if(minp[ssc_cnt]>w[y]) minp[ssc_cnt]=w[y], cnt_minp[ssc_cnt]=1;
            else if(minp[ssc_cnt]==w[y]) cnt_minp[ssc_cnt]++;
        }while(y!=u);
    }
}

int main()
{
    cin>>n;
    for(int i=1;i<=n;i++) scanf("%d",&w[i]);
    cin>>m;
    memset(h,-1,sizeof h);
    for(int i=0;i<m;i++)
    {
        int a,b;
        scanf("%d%d",&a,&b);
        add(a,b);
    }
    
    memset(minp,0x3f,sizeof minp);
    for(int i=1;i<=n;i++)
        if(!dfn[i])
            tarjan(i);
    
    ll res1=0, res2=1;
    for(int i=1;i<=ssc_cnt;i++)
    {    
        res1+=minp[i];
        res2=(ll)res2*cnt_minp[i]%mod;
    }
    
    cout<<res1<<' '<<res2<<endl;
    
    return 0;
}

猜你喜欢

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