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

这篇博客探讨了一种特殊的排序问题,仅允许使用Swap(0, i)操作来将给定的非负整数数组排序。文章通过实例解释了如何利用这种操作进行排序,并分类讨论了不同类型的环(单元环、含0多元环、非0多元环)及其所需的最少交换次数。最后,提供了输入处理、遍历环的操作以及问题总结,强调了解题的关键在于正确分类环的情况。" 115156089,10544332,无框架开发PHP:构建现代化应用的步骤,"['PHP', '无框架', 'PHP-DI', '中间件', '路由']
摘要由CSDN通过智能技术生成

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次交换;

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值