题意:
有n个房间,保证每一个房间只会通向另一个房间,有一只老鼠,初始房间不一定,它会在相通的房间内乱窜,你有无数个老鼠夹,可以放到任意房间内,保证老鼠已进入该房间就会被抓住,在不同的房间内放老鼠夹都会有一个对应的代价,问最少花费多少的代价,才能保证老鼠不管初始在哪个房间内都会被抓住。
思路:
tarjan+缩点,将一个强连通块缩为一个点,这个点的val为这个强连通块里的最小val,然后统计缩点后的DAG图里所有出度为0的点的val和就是答案。
#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 10;
int n, c[N], h[N], cnt, dfn[N], low[N], inde, val[N], ins[N], bel[N], x[N], chu[N], ans, minn[N];
stack<int> s;
struct node {
int v, net;
} no[N];
void add(int u, int v) {
no[cnt].v = v;
no[cnt].net = h[u];
h[u] = cnt++;
}
void tarjan(int u) {
int v;
s.push(u);
dfn[u] = low[u] = ++inde;
ins[u] = 1;
for(int i = h[u]; ~i; i = no[i].net) {
v = no[i].v;
if(!dfn[v]) {
tarjan(v);
low[u] = min(low[u], low[v]);
} else if(ins[v])
low[u] = min(low[u], dfn[v]);
}
if(dfn[u] == low[u]) {
minn[u] = min(minn[u], val[u]);
while(s.top() != u) {
v = s.top();
s.pop();
bel[v] = u, ins[v] = 0;
minn[u] = min(minn[u], val[v]);
}
s.pop();
ins[u] = 0, bel[u] = u;
}
}
int main() {
cin >> n;
memset(h, -1, sizeof h);
memset(minn, 0x3f, sizeof minn);
for(int i = 1; i <= n; i++) {
cin >> val[i];
}
for(int i = 1; i <= n; i++) {
cin >> x[i];
add(i, x[i]);
}
for(int i = 1; i <= n; i++)
if(!dfn[i])
tarjan(i);
for(int i = 1; i <= n; i++)
if(bel[i] != bel[x[i]])//强连通分量的出度个数
chu[bel[i]]++;
for(int i = 1; i <= n; i++)
if(!chu[i])
ans += minn[bel[i]], minn[bel[i]] = 0;//加完后置为0,防止重复加
cout << ans;
return 0;
}