C. Checkposts

_Yxc發表於2024-05-08

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';
}

相關文章