F. Selling a Menagerie
题目链接:https://codeforces.com/contest/1872/problem/F
思路
这个题需要用到拓扑排序,但和平常的拓扑排序又有差别,由题意可知,这是有 n n n个节点, n n n条边,这就必然存在一个环,我们可以先用拓扑排序把所有不成环的点先放进去,然后再对那个环单独处理。其实我们可以看出,对于一个环来说,最后一个去进行出售的,肯定不是以双倍价格出售的,这样我们就可以让这个环中成本最小的最后输出。
代码实现(参考佬的)
#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
//#define int long long
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const int N = 1e5 + 10;
const int P = 131; //转换成P进制
int t,n;
int a[N],c[N],deg[N];
bool vis[N];
vector<int> tp;
void dfs(int x) {
vis[x]=true;
tp.push_back(x);
if(--deg[a[x]]==0) dfs(a[x]);
}
void slove() {
cin>>n;
memset(deg,0,sizeof deg);
memset(vis,false,sizeof vis);
tp.clear();
for(int i=0; i<n; i++) {
cin>>a[i];
a[i]--;
deg[a[i]]++;
}
for(int i=0; i<n; i++) {
cin>>c[i];
}
for(int i=0; i<n; i++) { //拓扑排序
if(!vis[i] && deg[i]==0) dfs(i);
}
for(int i=0; i<n; i++) { //遍历找环
if(vis[i]) continue;
vector<int> h,v;
for(int j=i; !vis[j]; j=a[j]) { //找到环
vis[j]=true;
h.push_back(j);
v.push_back(c[j]);
}
int p=min_element(v.begin(),v.end())-v.begin(); //找到最小的那个点
for(int j=0; j<(int)h.size(); j++) {
tp.push_back(h[(p+1+j)%h.size()]);
}
}
for(int i=0; i<n; i++) cout<<tp[i]+1<<" "; //输出前n个点
cout<<"\n";
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
cin>>t;
while(t--) {
slove();
}
return 0;
}