• CodeForces


    CF1027D Mouse Hunt

    题目大意:

    n点n边有向图,可能包含自环和重边,现要求以最小花费选取一下点,使得无论从哪一个点出发都会经过所选的任意一个点。

    思路:

    我们考虑这样一种情况:

    1---->2<-----3
    ^-----|
    

    1、2号点形成一个环,3号点指向二号点。

    case 1:如果在1、2号点选一个最小花费点x,那么所有点必将经过点x,满足题意。

    case 2:如果选取了3号点,则必然不会比case 1的情况更优,因为总要在环内再选取一个点。

    我们使用拓扑排序可以得到图中所有环,对于每一个环dfs找到最小花费的点。

    Code:
    #include <bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    typedef pair<int, int> PI;
    const double eps = 1e-6;
    const int N = 200010;
    const int INF = 0x3f3f3f3f;
    const int mod = 1000000007; //998244353
    LL powmod(LL a, LL b) { LL res = 1; a %= mod; assert(b >= 0); for (; b; b >>= 1) { if (b & 1)res = res * a % mod; a = a * a % mod; }return res; }
    
    int n, c[N], deg[N], to[N], ans;
    bool vis[N];
    
    void topo(int x) { //拓扑排序,一直删入度为0的点
        vis[x] = 1;
        deg[to[x]]--; //模拟删点,即边的另一端入度--
        if (!deg[to[x]])
            topo(to[x]);
    }
    
    int dfs(int x) {
        vis[x] = 1;
        if (!vis[to[x]]) //取最小花费
            return min(dfs(to[x]), c[x]);
        else
            return c[x];
    }
    
    int main() {
        ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
        cin >> n;
        for (int i = 1; i <= n; i++) cin >> c[i];
        for (int i = 1; i <= n; i++) {
            int a; cin >> a;
            to[i] = a;
            deg[a]++;
        }
        for (int i = 1; i <= n; i++) {
            if (!deg[i] && !vis[i]) { //从没访问过的入度为0点开始
                topo(i);
            }
        }
        //到这一步为止,任意不在环上的点x,vis[x]=1
        for (int i = 1; i <= n; i++) {
            if (!vis[i]) 
                ans += dfs(i);
        }
        cout << ans << endl;
        return 0;
    }
    
  • 相关阅读:
    JavaSE_11_File类、递归
    JavaSE_10_IO流
    leyou_07_对数据的操作
    JavaSE_09_Map
    JavaSE_08_Collections常用功能
    java 22
    java 22
    java 22
    java 22
    java 22
  • 原文地址:https://www.cnblogs.com/Nepenthe8/p/14314173.html
Copyright © 2020-2023  润新知