在强连通图里 求最小值方案最小数
https://www.luogu.com.cn/problem/P2194
对每个连通块的值求里面的点的最小值 然后加起来就是遍历所有点的最小值
方案数就根据乘法原理乘起来就可以
#include <iostream>
#include <cstring>
#include <algorithm>
#include <unordered_map>
using namespace std;
unordered_map<string,int>cou;
const int N =100005, M=3e5+10;
int n,m;
int h[N], e[M], ne[M], idx;
int dfn[N],low[N],timestamp;
int stk[N],top;
bool in_stk[N];
int id[N],scc_cnt;
int din[N],dout[N];
int w[N];
int minn[N],sum[N];
void add(int a, int b) // 添加一条边a->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]){
++scc_cnt;
int y;
do{
y=stk[top--];
in_stk[y]=false;
id[y]=scc_cnt;
//如果和minn的值相等
if(minn[scc_cnt]==w[y]){//这两个if顺序不能调转
sum[scc_cnt]++;
}
//如果比minn的值小
if(w[y]<minn[scc_cnt]){
minn[scc_cnt]=w[y];
sum[scc_cnt]=1;
}
}while(y!=u);
}
}
int main()
{
cin>>n;
memset(h, -1, sizeof h);
memset(minn,0x3f,sizeof(minn));//注意minn表示连通块的值最小需要初始化的大 才会被更新
for(int i=1;i<=n;i++){
cin>>w[i];
}
int x,y;
cin>>m;
for (int i = 1; i <= m; i ++ ){
cin>>x>>y;
add( x,y );//这里反向边指回来
}
for (int i = 1; i <= n; i ++ )//tarjan 遍历所有点 所以是2*n
if(!dfn[i])
tarjan(i);
long long ans1=0,ans2=1;//ans1是最小值 ans2是方案书
for(int i=1;i<=scc_cnt;i++){
ans1=ans1+minn[i];
ans2=(ans2*sum[i])%1000000007;
}
cout<<ans1<<" "<<ans2<<endl;
return 0;
}