最少交换次数(暑假每日一题 24)

给定一个 1 ∼ N 1∼N 1N 的随机排列,要求一次只能交换相邻两个数,那么最少需要交换多少次才可以使数列按照从小到大排列呢?

请你求出一个待排序序列的最少交换次数和对应的逆序数列。

逆序数列:给定 n n n 个数 1 , 2 , … , n 1,2,…,n 1,2,,n 的一个排列 a 1 a 2 … a n a_1a_2…a_n a1a2an,令 b i b_i bi 是数 i i i 在此排列中的逆序数,换句话说, b i b_i bi 等于该排列中先于 i i i 又大于 i i i 的那些数的个数。数列 b 1 b 2 … b n b_1b_2…b_n b1b2bn 称为排列 a 1 a 2 … a n a_1a_2…a_n a1a2an 的逆序数列(inversion sequence)。

输入格式
第一行一个整数 N N N

第二行一个 1 ∼ N 1∼N 1N 的排列。

输出格式
第一行输出逆序数列,数之间用空格隔开。

第二行输出最少交换次数。

数据范围
1 ≤ N ≤ 1000 1≤N≤1000 1N1000

输入样例:

8
4 8 2 7 5 6 1 3

输出样例:

6 2 5 0 2 2 1 0
18

枚举 O( n 2 n^2 n2)

#include<iostream>

using namespace std;

const int N = 1010;

int n;
int q[N], cnt[N];

int main(){
    
    
    
    cin >> n;
    for(int i = 1; i <= n; i++) cin >> q[i];
    
    for(int i = 1; i <= n; i++)
        for(int j = 1; j < i; j++)
            if(q[j] > q[i]) cnt[q[i]]++;
        
    int res = 0;
    for(int i = 1; i <= n; i++)
        cout << cnt[i] << ' ', res += cnt[i];
    
    cout << '\n' << res;    
    
    return 0;
}

树状数组 O( n l o g n nlogn nlogn)

#include <iostream>

using namespace std;

const int N = 1010;

int n;
int tr[N], ans[N];

int lowbit(int x)
{
    
    
    return x & -x;
}

void add(int x, int v)
{
    
    
    for (int i = x; i <= n; i += lowbit(i))
        tr[i] += v;
}

int query(int x)
{
    
    
    int res = 0;
    for (int i = x; i; i -= lowbit(i))
        res += tr[i];
    return res;
}

int main()
{
    
    
    cin >> n;

    int sum = 0;
    for (int i = 0; i < n; i ++ )
    {
    
    
        int x;
        cin >> x;
        ans[x] = query(n) - query(x);
        sum += ans[x];
        add(x, 1);
    }

    for (int i = 1; i <= n; i ++ )
        cout << ans[i] << ' ';
    cout << endl << sum << endl;

    return 0;
}

归并排序 O( n l o g n nlogn nlogn)

#include <iostream>

using namespace std;

const int N = 1010;

int n;
int w[N], ans[N];
int q[N];

void merge_sort(int l, int r)
{
    
    
    if (l >= r) return;
    int mid = l + r >> 1;
    merge_sort(l, mid), merge_sort(mid + 1, r);

    int i = l, j = mid + 1, k = 0;
    while (i <= mid && j <= r)
        if (w[i] <= w[j]) q[k ++ ] = w[i ++ ];
        else
        {
    
    
            q[k ++ ] = w[j];
            ans[w[j]] += mid - i + 1;
            j ++ ;
        }

    while (i <= mid) q[k ++ ] = w[i ++ ];
    while (j <= r) q[k ++ ] = w[j ++ ];

    for (int i = l, j = 0; j < k; i ++, j ++ )
        w[i] = q[j];
}

int main()
{
    
    
    cin >> n;
    for (int i = 0; i < n; i ++ ) cin >> w[i];

    merge_sort(0, n - 1);

    int sum = 0;
    for (int i = 1; i <= n; i ++ )
    {
    
    
        cout << ans[i] << ' ';
        sum += ans[i];
    }

    cout << endl << sum << endl;

    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_46456049/article/details/126330139