Selling a Menagerie 的题解
题面大意
动物园里有
考虑卖掉这些动物时:
- 若
在 还没有卖掉之前就被卖掉了,现在卖掉 ,可以获得 元; - 若
在 还没有卖掉之前没被卖掉,现在卖掉 ,可以获得 元;
构造并输出赚钱最多的动物卖出顺序。
思路
显而易见,题目可以转化为图论进行解决。
将第
如果并没有其他的动物害怕第
因为这个图是一个基环树森林,所以在将所有的入度为
我们可以贪心的考虑删除掉环中的那一个点。
假设节点
这个环的价值就为
在每一次将环内的一个点卖出后,剩下的节点就可以通过拓扑序的方式依次删除。
注意,因为这是一个基环树森林,所以可能存在多个环。
AC Code
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e5+5;
int n,du[N],s[N];
vector<int> v[N];
queue<int> qq;
bool vis[N];
struct node{
int x,v;
friend bool operator < (const node a,const node b){
return a.v>b.v;
}
};
priority_queue<node>q;
void solve(){
cin>>n;
int cnt=0;
for(int i=1;i<=n;i++){
v[i].clear();
du[i]=0;
vis[i]=0;
s[i]=0;
}
while(!q.empty()){
q.pop();
}
for(int i=1,x;i<=n;i++){
cin>>x;
du[x]++;
v[i].push_back(x);
}
for(int i=1;i<=n;i++){
cin>>s[i];
}
for(int i=1;i<=n;i++){
if(du[i]==0){
qq.push(i);
cnt++;
vis[i]=1;
cout<<i<<" ";
}
}
while(!qq.empty()){
int x=qq.front();
qq.pop();
for(int i:v[x]){
du[i]--;
if(du[i]==0){
cout<<i<<" ";
qq.push(i);
vis[i]=1;
cnt++;
}
}
}
if(cnt==n){
return;
}
for(int i=1;i<=n;i++){
if(vis[i]){
continue;
}
int p=0;
while(vis[v[i][p]]) p++;
q.push({v[i][p],s[i]});
}
while(cnt<n){
while(vis[q.top().x]) q.pop();
qq.push(q.top().x);
cnt++;
vis[q.top().x]=1;
cout<<q.top().x<<" ";
while(!qq.empty()){
int x=qq.front();
qq.pop();
for(int i:v[x]){
du[i]--;
if(du[i]==0&&!vis[i]){
cout<<i<<" ";
qq.push(i);
cnt++;
vis[i]=1;
}
}
}
}cout<<endl;
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t;
cin>>t;
while(t--){
solve();
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】