PAT A1067 Sort with Swap(0, i)
Sample Input:
10
3 5 7 2 6 4 9 0 8 1
Sample Output:
9
word | meaning |
---|---|
permutation sequence | 排列顺序 |
-
分析:
要求只用swap(0, x),完成排序,且步数最少
刚一看,很蒙蔽,慢慢就发现了一个条件(这些数从0开始不间断),这个条件很重要!!
要想交换步数最少,根据贪心的原则,每次和0交换的元素都最优的选择,如果每次0都和他的下标的元素交换,就可以把下标元素排到最终位置,保证了每一步都是最优的选择
-》这时产生的问题有:
问题1.如何找到下标?
问题2.如果0交换到了0位置,而其他元素未完全有序怎么办? -
思路 1:
-》对应的解决方案:
问题1.使用一个下标数组Idex[]记录每个元素的下标,并且随着交换而同步更新
问题2.设一个变量right表示,左边已经排好序的序列的末尾(也就是从左往右第一个还没就位的位置),这样如果0换到0位置,下一次让他和right位置的元素交换,从而使循环能进行下去
由解决方案2很自然的想到 while 的退出条件就是right<n
-
code 1:
#include <stdio.h>
#include <algorithm> //swap函数
using namespace std;
const int maxn = 100010;
int num[maxn], idex[maxn];
int main(){
int n;
scanf("%d", &n);
for(int i = 0; i < n; ++i){
scanf("%d", &num[i]);
idex[num[i]] = i; //存储数字的所在的下标
}
int cnt = 0, right = 1; //right:最靠前的已经排好序的子序列的末位
while(right < n){
if(num[0] == 0){
swap(idex[num[right]], idex[0]); //!!!Wrong 1: 要先更新索引数组,否则num[right]先被交换了,出错
swap(num[0], num[right]);
}else{
int aim = idex[0];
swap(num[idex[0]], num[idex[aim]]);
swap(idex[aim], idex[0]); //更新索引数组
while(num[right] == right) right++;
}
cnt++;
}
printf("%d", cnt);
return 0;
}
- T3 code:
#include <bits/stdc++.h>
using namespace std;
vector<int> seq, pos;
void FindFirst(int & up){ while(pos[up] == up) up++; }
int main()
{
int n;
scanf("%d", &n);
seq.resize(n); pos.resize(n);
for(int i = 0; i < n; ++i)
{
scanf("%d", &seq[i]);
pos[seq[i]] = i;
}
int step = 0, upper = 0;
while(upper < n)
{
int pos0 = pos[0], pos_nex = pos[pos[0]];
if(pos[0] == 0)
{
FindFirst(upper);
pos_nex = upper;
}
if(upper < n)
{
swap(pos[0], pos[seq[pos_nex]]);
swap(seq[pos0], seq[pos_nex]);
step++;
}else printf("%d", step);
}
return 0;
}