「CF1872F」 Selling a Menagerie
题意
有 \(n\) 种动物,第 \(i\) 只动物有且只有一个害怕的动物 \(a_i\) 和价值 \(c_i\)。现在把所有的动物都卖出去,若 \(a_i\) 在 \(i\) 前面卖出去,将获得 \(c_i\) 的收益;否则将多获得 \(c_i\) 的收益。构造一种使收益最大的卖出顺序。
思路
这题很明显是图,显然对于每一个动物 \(i\),先卖 \(a_i\) 比先卖 \(i\) 更优。
可以从 \(i\) 向 \(a_i\) 连边,然后跑一遍拓扑,一边遍历一边输出当前节点。
但是,因为每个点都有一条出边,图中肯定会有一个环,拓扑后还剩下环内的节点没有考虑。
对于环内的点,先删去任何一个点都会影响后续的点,所以找到价值最小的点,从它开始删。
拓扑 \(O(n)\),遍历环 \(O(n)\),总时间复杂度 \(O(n)\)。
Code(无坑)
#include<bits/stdc++.h> using namespace std; typedef long long ll; #define read(x) scanf("%lld",&x) const ll maxn=100005; ll t,n,a[maxn],c[maxn],du[maxn],pre[maxn],mn[maxn]; vector<ll>h; inline ll find(ll x){return x==pre[x]?x:pre[x]=find(pre[x]);} inline void solve(){ read(n); for(ll i=1;i<=n;++i)pre[i]=i,du[i]=mn[i]=0; for(ll i=1;i<=n;++i)read(a[i]),++du[a[i]]; for(ll i=1;i<=n;++i)read(c[i]); queue<ll>p; for(ll i=1;i<=n;++i)if(!du[i])p.push(i); while(!p.empty()){ ll u=p.front();p.pop(); printf("%lld ",u); if(!--du[a[u]])p.push(a[u]); } for(ll i=1;i<=n;++i){ if(du[i]){ pre[find(i)]=find(a[i]); } } for(ll i=1;i<=n;++i){ if(du[i]&&(mn[find(i)]==0||c[mn[pre[i]]]>c[i])){ mn[pre[i]]=i; } } for(ll i=1;i<=n;++i){ if(du[i]&&mn[pre[i]]==i){ for(ll j=a[i];j!=i;j=a[j]){ printf("%lld ",j); } printf("%lld ",i); } } puts(""); } signed main(){ read(t); while(t--){ solve(); } return 0; }
本文作者:run-away
本文链接:https://www.cnblogs.com/run-away/p/18030324
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步