题目链接:http://codeforces.com/contest/427/problem/C
题目大意是有n个junctions,这些junctions之间有m条道路,两两相连,现在在junction上建立Checkposts,而且建立checkposts需要花费cost,如果某个点 i 建立了checkpost那么从这个点 i 开始绕一个环最终可以回到点 i ,那么途中经过的点都可以被监视到,问最少花费多少钱去建立checkposts才可以监视所有的junctions,建立checkposts的方案有多少种?
题解思路:刨析题意就是让你求有多少个强连通分量,用tarjan依次跑出每个强连通分量包含的点集,找出该集合中建立checkposts的最小花费,再求一下可以用最小花费建checkpost的junction的个数,最终的方案书就是每个强连通分量的 最小花费建checkpost的junction的个数连乘,最小花费就简单了,求一个强连通分量就加一下最小花费即可。
AC代码:
#include<iostream>
#include<stack>
#include<vector>
#include<algorithm>
#include<cmath>
using namespace std;
struct node{
vector<int> vex;
int cost;
};
node g[3000008];
int dfn[3000008];
int low[3000008];
int visit[3000008];
stack<int> stk;
vector<int> sum;
long long int Fcost = 0;
int tot ;
long long int mod = 1e9+7;
void tarjan(int x){
dfn[x] = low[x] = ++tot;
visit[x] = 1;
stk.push(x);
for(int i = 0;i<g[x].vex.size();i++ ){
if(!dfn[g[x].vex[i]]){
tarjan(g[x].vex[i]);
low[x] = min(low[x],low[g[x].vex[i]]);
}
else if(visit[g[x].vex[i]]){
low[x] = min(low[x],dfn[g[x].vex[i]]);
}
}
if(low[x] == dfn[x]){//找到一个强连通分量
int cnt = 1;
int Tcost = 0x3f3f3f3f;
while(x!=stk.top()){
visit[stk.top()] = 0;
if(g[stk.top()].cost < Tcost){
cnt = 1;//从这个强连通分量中找最小花费
Tcost = min(Tcost,g[stk.top()].cost);
}
else if(g[stk.top()].cost == Tcost){
cnt++;//记录最小花费点的个数
}
stk.pop();
}
visit[stk.top()] = 0;
if(g[stk.top()].cost < Tcost)
{
cnt = 1;
Tcost = min(Tcost,g[stk.top()].cost);
}
else if(g[stk.top()].cost == Tcost)
{
cnt++;
}
stk.pop();//这里是弹出栈内最后一个强连通分量的点
Fcost = (Fcost + Tcost);//Fcost是总花费
sum.push_back(cnt); //记录每个强连通分量的可以用最小花费点建立checkpost的个数
}
}
int main(){
int n;
cin>>n;
for(int i = 1;i<=n;i++){
int costI;
cin>>costI;
g[i].cost = costI;
}
int m;
cin>>m;
for(int i = 1;i<=m;i++){
int u,v;
cin>>u>>v;
g[u].vex.push_back(v);
}
for(int i = 1;i<=n;i++){//tarjan的板子,直接套一下
if(!dfn[i]){
tarjan(i);
}
}
long long int res = 1;
for(int i = 0;i<sum.size();i++){
res = (res*sum[i])%mod;
}
cout<<Fcost<<" "<<res;
return 0;
}