6.分治-逆序数对反转表

问题描述

Let { A1,A2,...,An } be a permutation of the set{ 1,2,..., n}. If i < j and Ai > Aj then the pair (Ai,Aj) is called an "inversion" of the permutation. For example, the permutation {3, 1, 4, 2} has three inversions: (3,1), (3,2) and (4,2). The inversion table B1,B2,...,Bn of the permutation { A1,A2,...,An } is obtained by letting Bj be the number of elements to the left of j that are greater than j. (In other words, Bj is the number of inversions whose second component is j.) For example, the permutation:

{ 5,9,1,8,2,6,4,7,3 }

has the inversion table

2 3 6 4 0 2 2 1 0.

since there are 2 numbers, 5 and 9, to the left of 1; 3 numbers, 5, 9 and 8, to the left of 2; etc. your task is to convert a permutation to its inversion table, or vise versa, to convert from an inversion table to the corresponding permutation. (Use divide and conquer method)

翻译

设 { A1,A2,...,An } 是集合 { 1,2,..., n} 的排列。如果 i < j 且 Ai > Aj,那么 (Ai,Aj) 对称为该排列的 "反转"。例如,排列 {3, 1, 4, 2} 有三个反转:(3,1)、(3,2) 和 (4,2)。将 Bj 设为 j 左边大于 j 的元素的个数,就可以得到排列 { A1,A2,...,An } 的反转表 B1,B2,...,Bn (换句话说,Bj 就是第二个分量是 j 的反转数):

{ 5,9,1,8,2,6,4,7,3 }

的反转表为

2 3 6 4 0 2 2 1 0.

因为在 1 的左边有 2 个数,即 5 和 9;在 2 的左边有 3 个数,即 5、9 和 8;等等。你的任务是将一个排列转换成它的反转表,或者反过来,将一个反转表转换成相应的排列。(使用分而治之法)

思路

待定

代码

#define  _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
#include <stdio.h>
#include <math.h>
#include <string>
#include <algorithm>
#include <stdlib.h>

using namespace std;
const int N = 1e6 + 10;
int resetTable[N] = { 0 }; int tem2[N] = { 0 };//复位答案
int inversionTable[N] = { 0 }; int ans = 0; int tem1[N];//反转表
void inverse(int a[], int l, int r)
{
	int mid = l + r >> 1;
	if (l <r)
	{
		inverse(a, l, mid );
		inverse(a, mid + 1, r);
	}
	int i = l, j = mid + 1, k = 0;
	while (i <= mid && j <= r)
	{
		if (a[i] <=a[j]) {
			tem1[k++] = a[i++]; 
		}
		else
		{
			tem1[k++] = a[j++];
			inversionTable[a[j - 1]] += mid-i+1;
		}
	}
	while (i <= mid)
	{		tem1[k++] = a[i++];
	}
	while (j <= r)
	{
		tem1[k++] = a[j++];
	}
	for (int i = l, j = 0; i <= r; j++, i++)
		a[i] = tem1[j];
}
void reSet(int a[], int n)
{

	int i,j,k, count;
	for (i = 1; i <= n; i++)
	{
		count = 0;
		for (j = 1; j <= n && count < a[i]; j++)
		{
			if (tem2[j] == 0)
			{		count++;
		}
		}//找到n个空位后,停止找空位,放入i
		if(tem2[j]!=0)//如果下一个位置不为空位,
			for(k=j+1;k<=n;k++)//遍历进行找空位
				if (tem2[k] == 0)
				{
					j = k;
					break;
				}
		tem2[j] = i;//在下一个位置放入i
	}
	//int i, j, count, k;

	//for (i = 1; i <= n; i++)
	//{
	//	count = 0;

	//	for (j = 1; j <= n && count < a[i]; j++)
	//	{                                                         // 扫描寻找 符合的位置
	//		if (tem2[j] == 0)
	//			count++;
	//	}

	//	if (tem2[j] != 0)     // 位置发生了冲突。
	//		for (k = j + 1; k <= n; k++)
	//			if (tem2[k] == 0)
	//			{
	//				j = k;
	//				break;
	//			}
	//	tem2[j] = i;

	//}
}
int main()
{
	int n;
	cin >> n;
	int a[N];
	for (int i = 1; i <= n; i++)
	{
		cin >> a[i];
	}
	inverse(a, 1,n);
	cout << "The  inversion table is following :" << endl;
	for (int i = 1; i <= n; i++)
		cout << inversionTable[i] << " ";
	reSet(inversionTable, n);
	cout << endl;
	cout << "The reSet table is following :" << endl;
	for(int i=1;i<=n;i++)
		cout << tem2[i] << " ";
	return 0;
}

测试案例

运行结果

时间复杂度分析

速记

  • 11
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

熟人看不到

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值