2021 ICPC昆明 K. Parallel Sort
2021 ICPC昆明 K. Parallel Sort
题意
给一个\(1\) 到 \(n\) 的排列,每一回合可以选择若干对这一回合未使用过的数进行交换,最终将数列归位
输出最少回合次数,输出操作方案
sol
首先可以想到,,对于每个数和他该在的位置连边的话(\(a[i] \rightarrow a[a[i]]\)) ,就会形成若干个边
如\(6,1,2,3,4,5\) 会构成\(6\rightarrow5\rightarrow4\rightarrow3\rightarrow2\rightarrow1\rightarrow6\) 的环
如果环的大小等于二的话,直接换过来就可,round = 1
否则的话两个边换\((6,1),(5,2),(4,3)\) 发现这样一换之后一个环就会被拆分成若干个大小为2的环
所以操作回合至多为两次
code
int n,m;
int a[maxn];
int vis[maxn];
std::vector<std::vector<pii> > ans;
std::vector<pii> f() {
std::vector<pii> an;
CLR(vis,0);
for(int i = 1; i <= n; i++) {
if(a[i] == i) continue;
if(!vis[i]) {
std::vector<int> v;
int p = i;
while(!vis[p]) {
v.PB(p);
vis[p] = 1;
p = a[p];
}
int m = v.size();
for(int l = 0,r = m-1; l < r; l++,r--) {
swap(a[v[l]],a[v[r]]);
an.PB(make_pair(v[l],v[r]));
}
}
}
return an;
}
int main() {
cin >> n;
for(int i = 1; i <= n; i++) {
cin >> a[i];
}
for(;;) {
auto p = f();
if(p.empty()) break;
else ans.PB(p);
}
cout << ans.size() << "\n";
for(auto k : ans) {
cout << k.size() << " ";
for(auto i : k)
cout << i.first << " " << i.second << " ";
cout << "\n";
}
return 0;
}

浙公网安备 33010602011771号