题目大意:
给出0, 1.. N-1的一个序列,要求通过两两交换的方式将其变为递增序列,但是规定每次只能用0与其他数进行交换。求最小交换次数。
算法思路:
根据题目给出的交换例子,仔细观察可以知道其交换策略为:如果数字0当前在i号位,则找到数字i当前所处的位置,然后把0与i进行交换。但是仔细思考发现如果数字0在0位置就无法继续执行下去,所以对于该策略,需要对于数字0在位置0上进行特判,将数字0与序列中任意一个不在本位上的数字进行交换,这样策略就可以继续进行下去,直到数字0在0位置上,并且其他数字都在其本位说明交换结束。由于每一次交换都会一个数字放到本位(数字0在0位置除外),基本可以认为这就是交换次数最小的策略
提交结果:
第一次测试:测试点1和2超时,原因是每次查找不在本位上的数字都是从头去找。
解决方法:使用数字j保存不在本位上的最小数字,初始为0,然后都与j进行交换,那么每次遇到0在本位上的时候,就可以和直接从j进行查找最小的不在本位上的数字,因为小于数字j的都已经在本位上了。
注意点:
1、建立数字到下标的映射会比较方便操作,因为每一次都需要找到下标,并且下标的交换也就相当于是数字的交换。
2、使用一个数字记录上一次交换中不在本位上的最小数字j,这样在数字0在本位寻找不在本位上的数字的时候就可以从j开始找,不然测试点1和2会超时。
3、此题虽然题目不难理解,但是实现过程是真的心累((╥╯^╰╥)),特别容易出现死循环。
AC代码:
#include <cstdio>
#include <algorithm>
using namespace std;
int main(){
int N;
scanf("%d",&N);
int indexs[N];// 保存所有数字对应的地址
int a;
for (int i = 0; i < N; ++i) {
scanf("%d",&a);
indexs[a] = i;//数字a的位置为i
}
int num = 0;//交换次数
int j = 0;//不在本位上的最小数字
while (true){
// 首先判断当前数字0是否在0位置上
if(indexs[0]==0){
// 找到任意一个不在本位上的数字i与0进行交换
bool isAllinPosition = true;// 是否所有的数字都在本位上
int i = 1;
for (; j < N; ++j) {
if(indexs[j]!=j){
i = j;
isAllinPosition = false;
break;
}
}
if(isAllinPosition) break;
swap(indexs[i],indexs[0]);
++num;
} else {
// 将数字0和数字indexs[0]进行交换
swap(indexs[0],indexs[indexs[0]]);
++num;
}
}
printf("%d",num);
return 0;
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。