题目大意:
有(n)个房间,保证每一个房间只会通向另一个房间(a[i]) (可能会通向自己,可能有多个房间通向一个房间)。有一只老鼠会在相通的房间内乱窜。你可以以代价(c[i])放置老鼠夹到任意房间内。求最小代价使得老鼠无论逃窜在哪都会被抓。
思路:
模拟样例即可发现,我们可以将图通过(tarjan)缩点变成(DAG)后,统计出度为(0)的强连通分量个数即为要放置的老鼠夹的数量。在每个强连通分量中记录代价最小的花费。
Code:
#include <bits/stdc++.h>
using namespace std;
const int N = 200010;
const int INF = 0x3f3f3f3f;
struct Node {
int to, next;
} e[N << 1];
int head[N], tot;
int dfn[N], low[N], num;
int co[N], col, minn[N];
bool vis[N];
int st[N], top;
int n, c[N], a[N], ans, out[N];
void add_edge(int u, int v) {
e[++tot].to = v;
e[tot].next = head[u];
head[u] = tot;
}
void tarjan(int u) {
dfn[u] = low[u] = ++num;
vis[u] = 1;
st[++top] = u;
for (int i = head[u]; ~i; i = e[i].next) {
int v = e[i].to;
if (!dfn[v]) {
tarjan(v);
low[u] = min(low[u], low[v]);
} else if (vis[v]) {
low[u] = min(low[u], dfn[v]);
}
}
if (low[u] == dfn[u]) {
co[u] = ++col;
while (st[top] != u) {
co[st[top]] = col;
minn[col] = min(minn[col], c[st[top]]);
vis[st[top--]] = 0;
}
minn[col] = min(minn[col], c[st[top]]);
vis[st[top--]] = 0;
}
}
int main() {
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
memset(head, -1, sizeof(head));
memset(minn, 0x3f, sizeof(minn));
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> c[i];
}
for (int i = 1; i <= n; i++) {
cin >> a[i];
add_edge(i, a[i]);
}
for (int i = 1; i <= n; i++) {
if (!dfn[i]) tarjan(i);
}
for (int i = 1; i <= n; i++) {
if (co[i] != co[a[i]]) {
out[co[i]]++;
}
}
for (int i = 1; i <= n; i++) {
if (!out[co[i]]) {
ans += minn[co[i]];
minn[co[i]] = 0;
}
}
cout << ans << endl;
return 0;
}