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个元素:不需要交换
- 环里n0个元素,包括0:需要n0–1次交换
- 第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次交换;