CodeForces - 1027D Mouse Hunt(拓扑排序、dfs)

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;
}
posted @ 2021-01-22 16:47  Nepenthe8  阅读(90)  评论(0)    收藏  举报