https://codeforces.com/contest/427/problem/C
題意:給個圖,每個點是一個junction,在junction可以建立一個checkpost,不同的junction建立checkpost有不同的代價。但是如果兩個junction是強連通的,那麼可以在這兩個junction中任意建立一個。
求建立checkpost的最小代價,以及在當前最小代價下,有多少種建立checkpost的方式。
思路:tarjan演算法求強連通分量,然後對每個分量遍歷,找出最小的代價和對應的數量,累計到答案中即可。
總結:第一次寫圖中的強連通分量題目,目前對圖的掌握還停留在鄰接表的dfs或者bfs,或者簡單的dp中。。tarjan演算法的核心思想是,如果當前點沒有被訪問,則dfs。在dfs過程中記錄一個low和一個dfn陣列,這兩個陣列分別記錄了最小訪問時間戳和正常訪問時間戳。並且還需要一個棧。當low和dfn的值相等時,當前點就是一個連通分量的頭節點,在棧中比這個點高的點就是連通分量中的其他節點。
class Tarjan{
public:
Tarjan(const vector<vector<int>>& s):
sz_((int)s.size()),
al_(s),
low_(sz_, -1),
dfn_(sz_, -1),
in_stack_(sz_, false),
timer_(0){}
//strongly connected component
vector<vector<int>> getScc(){
for (int i = 0; i < sz_; ++i){
if (dfn_[i] == -1){
dfsScc(i);
}
}
return components_;
}
private:
int sz_;
vector<vector<int>> al_;
vector<vector<int>> components_;
vector<int> low_;
vector<int> dfn_;
vector<bool> in_stack_;
stack<int> stk_;
int timer_;
void dfsScc(int u){
low_[u] = dfn_[u] = timer_ ++;
in_stack_[u] = true;
stk_.push(u);
for (const auto& v : al_[u]){
if (dfn_[v] == -1){
dfsScc(v);
low_[u] = min(low_[u], low_[v]);
}
else if (in_stack_[v] == true){
low_[u] = min(low_[u], low_[v]);
}
}
//head of strongly connected component
if (low_[u] == dfn_[u]){
components_.emplace_back();
while (!stk_.empty()){
int cur = stk_.top();
stk_.pop();
components_.back().emplace_back(cur);
in_stack_[cur] = false;
if (cur == u){
break;
}
}
}
}
};
void preProcess(){
}
constexpr int mod = 1e9 + 7;
void solve(){
int n;
cin >> n;
vector<int> a(n);
for (auto& x : a){
cin >> x;
}
int m;
cin >> m;
vector<vector<int>> al(n);
for (int i = 0; i < m; ++i){
int u, v;
cin >> u >> v;
u --;
v --;
al[u].emplace_back(v);
}
Tarjan tarjan(al);
auto components = tarjan.getScc();
pair<long long, long long> ans{0ll, 1ll};
for (const auto& comp : components){
long long cost = (long long)1e18;
long long cnt = 1;
for (const auto& cur : comp){
if (checkMin(cost, a[cur])){
cnt = 1;
}
else if (cost == a[cur]){
cnt ++;
}
}
ans.first += cost;
ans.second = ans.second * cnt % mod;
}
cout << ans.first << ' ' << ans.second << '\n';
}