表排序+环的分类 1067 Sort with Swap(0, i) (25分)

1067 Sort with Swap(0, i) (25分)

Given any permutation of the numbers {0, 1, 2,…, N−1}, it is easy to sort them in increasing order. But what if Swap(0, *) is the ONLY operation that is allowed to use? For example, to sort {4, 0, 2, 1, 3} we may apply the swap operations in the following way:

Swap(0, 1) => {4, 1, 2, 0, 3}
Swap(0, 3) => {4, 1, 2, 3, 0}
Swap(0, 4) => {0, 1, 2, 3, 4}

Now you are asked to find the minimum number of swaps need to sort the given permutation of the first N nonnegative integers.

Input Specification:
Each input file contains one test case, which gives a positive N (≤10
​5
​​ ) followed by a permutation sequence of {0, 1, …, N−1}. All the numbers in a line are separated by a space.

Output Specification:
For each case, simply print in a line the minimum number of swaps need to sort the given permutation.

Sample Input:

10
3 5 7 2 6 4 9 0 8 1

Sample Output:

9

解题
只用0交换,把给定数组变换为顺序数组最短需要几次交换;
此排序交换方法思路就是若0在别的位置上,把0与改位置交换,直到0回到0位置;
若0在0位置上,把0与任意不在原本位置上的数交换,再进行如上操作;


给定数组由若干个环构成;
环分3种

  1. 只有1个元素:不需要交换
  2. 环里n0个元素,包括0:需要n0–1次交换
  3. 第i个环里有ni个元素,不包括0:先把0换到环里,再
    进行(ni+1)–1次交换 —— 一共是ni+1次交换

若N个元素的序列中包含S个单元环、1个含0多元环,K-1个非0多元环,则交换次数为:N-S+K-2,此公式默认0一开始在一个多元环内;
若0一开始在单元环0中,则K全部为无0多元环,公式为N-S+K;

1.输入函数

void input()
{
	cin>>N;
	for(int i=0;i<N;i++)
	{
		cin>>T[i];
		if(T[i]==i) S++;
		R[T[i]]=i;       //T[i]中i的位置在R[i]内 
	}
}

把数组保存在T中,R【i】中保存i在T中的位置,T【R【i】】即为i;
且若数原本就在自身位置,即为单元环,S计数+1;

2.遍历环操作
首先判断T【0】是否为0,是的话结果需要+2;
接着遍历T,每找到一个不在序号位置上的数,则保存到temp,把T【R【i】】赋值给T【i】,此时i归为,接着i=R【i】,继续操作,直到i与一temp相同,说明该环遍历完成;

void calculate()
{
	//计算
	if(T[0]==0) flag=2;
	int K=0; 
	for(int i=0;i<N;i++)
	{
		if(T[i]!=i)
		{				
			int tmp=T[i];
			int t=i;
			int r=R[i];
			while(t!=tmp)      //t是当前的序号等于开头拿出的值。 
			{
				T[t]=T[r];
				//完成转移 
				t=r;
				r=R[t];
			}
			T[t]=tmp;
			K++;
		}
	}
	
	cout<<N-S+K-2+flag;
} 

完整代码

#include<iostream>
#include<algorithm>
using namespace std;
const int maxn =100010;

int N;
int T[maxn];
int R[maxn];
int S=0;
int flag=0;
void input()
{
	cin>>N;
	for(int i=0;i<N;i++)
	{
		cin>>T[i];
		if(T[i]==i) S++;
		R[T[i]]=i;       //T[i]中i的位置在R[i]内 
	}
}

void calculate()
{
	//计算
	if(T[0]==0) flag=2;
	int K=0; 
	for(int i=0;i<N;i++)
	{
		if(T[i]!=i)
		{				
			int tmp=T[i];
			int t=i;
			int r=R[i];
			while(t!=tmp)      //t是当前的序号等于开头拿出的值。 
			{
				T[t]=T[r];
				//完成转移 
				t=r;
				r=R[t];
			}
			T[t]=tmp;
			K++;
		}
	}
	
	cout<<N-S+K-2+flag;
} 

int main()
{
 	input();
	calculate();
	
}

总结
该题难点在于分类三种环的情况;
首先交换0的排序方法符合环操作;
若环里有N个元素,需要N-1次交换可以全部归位;
若0不在环里,把0放到环里1次+(N+1)-1次交换,一共N+1次交换;

发布了105 篇原创文章 · 获赞 6 · 访问量 4939

猜你喜欢

转载自blog.csdn.net/BLUEsang/article/details/105612932