给定一个 1 ∼ N 1∼N 1∼N 的随机排列,要求一次只能交换相邻两个数,那么最少需要交换多少次才可以使数列按照从小到大排列呢?
请你求出一个待排序序列的最少交换次数和对应的逆序数列。
逆序数列:给定 n n n 个数 1 , 2 , … , n 1,2,…,n 1,2,…,n 的一个排列 a 1 a 2 … a n a_1a_2…a_n a1a2…an,令 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 b1b2…bn 称为排列 a 1 a 2 … a n a_1a_2…a_n a1a2…an 的逆序数列(inversion sequence)。
输入格式
第一行一个整数 N N N。
第二行一个 1 ∼ N 1∼N 1∼N 的排列。
输出格式
第一行输出逆序数列,数之间用空格隔开。
第二行输出最少交换次数。
数据范围
1 ≤ N ≤ 1000 1≤N≤1000 1≤N≤1000
输入样例:
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;
}