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

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

题意:

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

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

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

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

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

输入:

首 行 一 个 正 整 数 n , 首行一个正整数n, n

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

然 后 输 入 正 整 数 m , 然后输入正整数m, m

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

输出:

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

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 1n1050m31050wi1091ui,vin;u=v


分析:

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

首 先 通 过 t a r j a n 算 法 求 强 连 通 分 量 , 同 时 维 护 两 个 数 组 m i n p 和 c n t _ m i n p , 首先通过tarjan算法求强连通分量,同时维护两个数组minp和cnt\_minp, tarjanminpcnt_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=1ssc_cntminp[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]。 i=1ssc_cntcnt_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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值