洛谷 P2194 HXY烧情侣Tarjan缩点 分析+题解代码

Posted niiick

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了洛谷 P2194 HXY烧情侣Tarjan缩点 分析+题解代码相关的知识,希望对你有一定的参考价值。

洛谷 P2194 HXY烧情侣【Tarjan缩点】 分析+题解代码


题目描述:

众所周知,HXY已经加入了FFF团。现在她要开始喜(sang)闻(xin)乐(bing)见(kuang)地烧情侣了。这里有n座电影院,n对情侣分别在每座电影院里,然后电影院里都有汽油,但是要使用它需要一定的费用。m条单向通道连接相邻的两对情侣所在电影院。然后HXY有个绝技,如果她能从一个点开始烧,最后回到这个点,那么烧这条回路上的情侣的费用只需要该点的汽油费即可。并且每对情侣只需烧一遍,电影院可以重复去。然后她想花尽可能少的费用烧掉所有的情侣。问最少需要多少费用,并且当费用最少时的方案数是多少?由于方案数可能过大,所以请输出方案数对1e9+7取模的结果。

(注:这里HXY每次可以从任何一个点开始走回路。就是说一个回路走完了,下一个开始位置可以任选。所以说不存在烧不了所有情侣的情况,即使图不连通,HXY自行选择顶点进行烧情侣行动。且走过的道路可以重复走。)

输入格式:

第一行,一个整数n。

第二行,n个整数,表示n个情侣所在点的汽油费。

第三行,一个整数m。

接下来m行,每行两个整数xi,yi,表示从点xi可以走到yi。

输出格式:

一行,两个整数,第一个数是最少费用,第二个数是最少费用时的方案数对1e9+7取模

输入样例#1:

3
1 2 3
3
1 2
2 3
3 2

输出样例#1:

3 1

输入样例#2:

3
10 20 10
4
1 2
1 3
3 1
2 1

输出样例#2:

10 2

说明:

数据范围:

对于30%的数据,1<=n,m<=20;

对于10%的数据,保证不存在回路。

对于100%的数据,1<=n<=100000,1<=m<=300000。所有输入数据保证不超过10^9。


题目分析:

一道典型的tarjan缩点裸题

不会tarjan的小伙伴可以参考我的另一篇博客
图论算法-Tarjan模板 【缩点;割顶;双连通分量】

tarjan缩点后每个强连通分量中最小的点权相加即为所求最小值
方案数可运用乘法原理
记录每个缩点中有几个最小的点权
在相乘时取膜即可


献上蒟蒻代码

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<vector>
#include<cstring>
#include<stack>
using namespace std;

int n,m;
int w[1000010];
vector<int> map[100010];
int dfn[100010],low[100010];
int col[100010];
int tot,colnum;
stack<int> st;
bool ins[100010];
int minn[100010];//记录每个强连通分量中的最小点权
int num[100010];//记录每个强连通分量有几个最小点权
int ans;//最小花费
int sum=1;//方案数

void tarjan(int u)
{
    low[u]=dfn[u]=++tot;
    st.push(u);
    ins[u]=true;
    
    for(int j=0;j<map[u].size();j++)
    {
        int v=map[u][j];
        if(!dfn[v])
        {
            tarjan(v);
            low[u]=min(low[u],low[v]);
        }
        
        else if(ins[v])
        low[u]=min(low[u],dfn[v]);
    }
    
    if(low[u]==dfn[u])
    {
        colnum++;
        int temp;
        do
        {
            temp=st.top();
            st.pop();
            ins[temp]=false;
            
            col[temp]=colnum;
            
            if(w[temp]<minn[colnum])
            {
                //更新最小值及最小值个数
                minn[colnum]=w[temp];
                num[colnum]=1;
            }
            
            else if(w[temp]==minn[colnum])
            num[colnum]++;//更新最小点权数
        }
        while(temp!=u);
    }
}

int main()
{
    cin>>n;
    for(int i=1;i<=n;i++)
    cin>>w[i];
    
    cin>>m;
    for(int i=1;i<=m;i++)
    {
        int s,t;
        cin>>s>>t;
        map[s].push_back(t);
    }
    
    memset(minn,127,sizeof(minn));
    for(int i=1;i<=n;i++)
    {
        if(!dfn[i])
        tarjan(i);
    }
    
    for(int i=1;i<=colnum;i++)
    {
        ans+=minn[i];
        sum*=num[i]%1000000007;
    }
    
    cout<<ans<<" "<<sum;
    
    return 0;
}

以上是关于洛谷 P2194 HXY烧情侣Tarjan缩点 分析+题解代码的主要内容,如果未能解决你的问题,请参考以下文章

P2194 HXY烧情侣(tarjan&组合数学)

P2194 HXY烧情侣Tarjan

luogu P2194 HXY烧情侣 题解

P2194 HXY烧情侣

HXY烧情侣(洛谷 2194)

HXY烧情侣