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 4 2 1 3的情况,也就是0号元素已就位该怎么办。
那我们此时只能进行一次看似多余但并不多余的交换。就是找到0号位置后面第一个还未就位的数字。比如要想把4就位,就必须swap(0,1) 然后再重复上面黑体字的操作。
如果仅仅做到这些还并不能得满分,线性找0号位后面的未就位数字是会超时的,我们应该想个办法。详见代码。
#include<bits/stdc++.h>
#define maxn 100001
using namespace std;
int n,cnt;
int data[maxn];
void swap(int i,int j){
cnt++;
int tmp;
tmp=data[i];
data[i]=data[j];
data[j]=tmp;
}
int main(){
set<int>st;//用于存放还未就位的数的下标
scanf("%d",&n);
for(int i=0;i<n;i++){
scanf("%d",&data[i]);
if(data[i]!=i&&i!=0)//0位置不能存
st.insert(i);
}
int idx;
while(!st.empty()){
if(data[0]!=0){
st.erase(data[0]);//一定要先删除再交换,原因很简单自己想
swap(0,data[0]);
}
else{
idx=*st.begin();
st.erase(idx);
swap(0,idx);
st.insert(idx);//进行这次多余交换后,idx位置就成为了未就位的位置,应当重新插入set中
}
}
printf("%d",cnt);
}