1. 程式人生 > 實用技巧 >習題:Inversion SwapSort(思維)

習題:Inversion SwapSort(思維)

題目

傳送門

思路

比較巧妙的一道構造題

首先考慮排列的情況

因為是排列,所以每一個數位上的最終狀態一定是固定的

\(b_i\)滿足\(a_{b_i}=i\)

如果交換\(a_{b_i},a_{b_j}\),那麼\(b_i,b_j\)一定也會被交換

再者,如果\(a\)有序,那麼\(b\)一定也有序,反之亦然

考慮逆序對對映到\(b\)上會是什麼情況

\(b_i<b_j,a_{b_i}>a_{b_j}\)

考慮到\(b\)陣列的定義

\(a_{b_i}>a_{b_j}\Rightarrow i>j\)

即對於\(b\)陣列,每一對滿足\(\begin{cases}b_i<b_j\\i>j\end{cases}\)

都需要被交換,此處\(i和j\)是等價的,所以也可以寫成\(\begin{cases}b_i>b_j\\i<j\end{cases}\)

此處容易發現這就是逆序對的形式,同時,對於\(a\)的逆序對,\(b\)一定有一個唯一的與其對應

即我們將b進行一個氣泡排序即可

記錄下需要交換的\(b_i,b_{i+1}\)

那麼對於數列的情況也是一樣的,用兩個關鍵字來表示一個數即可

程式碼

#include<iostream>
#include<algorithm>
#include<map>
#include<vector>
using namespace std;
#define x first
#define y second
int n;
int b[1005];
pair<int,int> a[1005],c[1005];
map<int,int> tot;
vector<pair<int,int> > ans;
int main()
{
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        cin>>a[i].x;
        a[i].y=++tot[a[i].x];
        c[i]=a[i];
    }
    sort(c+1,c+n+1);
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            if(c[i]==a[j])
            {
                b[i]=j;
                break;
            }
        }
    }
    for(int i=n;i>=1;i--)
    {
        for(int j=1;j<i;j++)
        {
            if(b[j]>b[j+1])
            {
                swap(b[j],b[j+1]);
                ans.push_back(make_pair(b[j],b[j+1]));
            }   
        }
    }
    cout<<ans.size()<<endl;
    for(int i=0;i<ans.size();i++)
        cout<<ans[i].x<<' '<<ans[i].y<<endl;
    return 0;  
}