Educational Codeforces Round 49 (Rated for Div. 2) D. Mouse Hunt (tarjan缩点)

-
题意:有一只老鼠,有\(n\)个位置,刚开始老鼠可能出现在任意位置,然后每次跑去第\(a_i\)个位置,如果\(i=a_i\)那么它就会停下,你可以在第\(i\)个位置花费\(c_i\)放置老鼠夹,你想要话费最小的代价来保证能抓到老鼠,问最小代价是多少.
-
题解:我们可以把数组\(a\)抽象成一张有向图,容易发现,对于一条链,我们只要在链末放一个夹子就够了,因为假如老鼠在链末,它哪儿都不能去,那么链末就一定要放一个夹子,而这条链上的所有点都会走到链末,那么只要链末有一个就够了.对于强连通分量,我们可以用tarjan缩点,同时维护强连通分量中的最小值,那么最后我们只要求一下所有出度为\(0\)的点的花费即可.
-
代码:
#include <bits/stdc++.h> #define ll long long #define fi first #define se second #define pb push_back #define me memset #define rep(a,b,c) for(int a=b;a<=c;++a) #define per(a,b,c) for(int a=b;a>=c;--a) const int N = 1e6 + 10; const int mod = 1e9 + 7; const int INF = 0x3f3f3f3f; using namespace std; typedef pair<int,int> PII; typedef pair<ll,ll> PLL; ll gcd(ll a,ll b) {return b?gcd(b,a%b):a;} ll lcm(ll a,ll b) {return a/gcd(a,b)*b;} int n; int c[N]; int dfn[N],low[N],timestamp; int stk[N],top; bool in_stk[N]; int id[N],scc_cnt; vector<int> edge[N]; int res[N]; int out[N]; void tarjan(int u){ dfn[u]=low[u]=++timestamp; stk[++top]=u,in_stk[u]=true; for(auto w:edge[u]){ if(!dfn[w]){ tarjan(w); low[u]=min(low[u],low[w]); } else if(in_stk[w]) low[u]=min(low[u],dfn[w]); } if(dfn[u]==low[u]){ ++scc_cnt; int y; do{ y=stk[top--]; in_stk[y]=false; id[y]=scc_cnt; res[scc_cnt]=min(res[scc_cnt],c[y]); }while(u!=y); } } int main() { ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); int n; cin>>n; me(res,INF,sizeof(res)); rep(i,1,n) cin>>c[i]; rep(i,1,n){ int v; cin>>v; edge[i].pb(v); } rep(i,1,n){ if(!dfn[i]) tarjan(i); } rep(i,1,n){ for(auto w:edge[i]){ int fu=id[i]; int fv=id[w]; if(fu==fv) continue; out[fu]++; } } int ans=0; rep(i,1,scc_cnt){ if(out[i]) continue; ans+=res[i]; } cout<<ans<<'\n'; return 0; }
𝓐𝓬𝓱𝓲𝓮𝓿𝓮𝓶𝓮𝓷𝓽 𝓹𝓻𝓸𝓿𝓲𝓭𝓮𝓼 𝓽𝓱𝓮 𝓸𝓷𝓵𝔂 𝓻𝓮𝓪𝓵
𝓹𝓵𝓮𝓪𝓼𝓾𝓻𝓮 𝓲𝓷 𝓵𝓲𝓯𝓮

浙公网安备 33010602011771号