解题思路1、紧紧抓住条件,课程编号只有1-n,那么实际上每个课程最后只会放入数组相应的下标,比如有数据:
3 4 5 2 1
那么最后课程编号3只能被放入第三个位置,课程编号1只能放入第一个位置。
因此首先有个绝对不可能成功的判定条件:
那就是奇数课程编号只能放在奇数的下标位置、偶数的课程编号只能放在偶数的下标位置!!!!因为每次换是隔一个的。
if(a[i]%2 != (i+1)%2){
printf("-1\n");
tag = 1;
break;
}
然后就是怎么换次数最少?
实际上我们根本就不用理会中间的过程,值需要知道课程编号为5的一定要放到第五个位置去,那当然我们直奔目标是最快的!!!!
所以直接计算课程编号和当前位置爹差值/2就是最少的操作次数,举例:
课程编号5,应该放在第五个位置,但是目前挡灾第3个位置,因此需要挪动的最少次数是(5-3)/2 = 1
其余同理,然后我们每次值需要计算课程编号应该放的位置比当前的位置大的即可,其余的情况会在我们排列的时候自动排列好!!!
//只需要标号大的懂,小的自己就排列好了
if(a[i]-i>1)
ans += (a[i]-(i+1))/2;
下面是思路的整体代码:
#include <stdio.h>
int main()
{
int a[1086];
int t, n, i, j, k=1, tag=0, ans;
scanf("%d", &t);
while (k<=t)
{
k++;
scanf("%d",&n);
// 这不是坑我胖虎吗,数组一般都是从0开始读取,哪有从1的
for(i=0;i<n;i++)
scanf("%d",&a[i]);
/*
解题关键是发现规律,编号为i的课程一定要放到数组下标i的位置,然后因为每次交换都是
隔一个进行交换,那么因为课程编号的奇、偶性一定不会变化,比如有:
3 4 1 5 2
2在第5个位置,那么不管怎么交换都只能在奇数的位置上(第一个、第三个、第五个)
因此如何用最少的次数放回正确的位置呢??这是这个题目的难点
*/
ans = 0;
for(i = 0;i < n;i++){
if(a[i]%2 != (i+1)%2){
printf("-1\n");
tag = 1;
break;
}
//只需要标号大的懂,小的自己就排列好了
if(a[i]-i>1)
ans += (a[i]-(i+1))/2;
//printf("ans:%d\n",ans);
}
if(tag!=1) printf("%d\n",ans);
tag = 0;
}
return 0;
}
这个算法的时间复杂度是O(N)
解题思路二、可以利用dfs(deep first search,深度优先遍历,类似之前数组变换拿到题目,这个解法我先不写,你先掌握上面哪个)