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;
}
posted @ 2021-04-05 22:36  EnthalpyDecreaser  阅读(102)  评论(0)    收藏  举报