要完成这题且不超时,必须得知道下面这个结论(之前我自己找到了一种方法但测试点一和二过不了,超时了):N个数字(这N个数的值为0到N-1且没有重复的数字)的排列一定由若干个环组成 ,且这些环互不相交。
那么什么叫环呢?假设这N个数存在大小为N的数组a[N]中,随便选一个数a[i],若i=a[i]则这个数自成一个环,否则temp=i;while ( a[i] != temp ) i=a[i] ;当循环退出时则找到了一个环。
如下表,8个数的排列中有三个环(颜色相同表示属于同一个环):
A | 【0】 | 【1】 | 【2】 | 【3】 | 【4】 | 【5】 | 【6】 | 【7】 |
---|---|---|---|---|---|---|---|---|
data | 3 | 5 | 2 | 1 | 7 | 0 | 4 | 6 |
且环的类型有三种
- 环中只有一个元素,这样的环a[i]==i,说明他已经有序,不需要调整
- 环中有n个元素(n>=2),且元素0在该环中,此时需要经过n-1次交换使环中的元素有序
- 环中有n个元素(n>=2),且元素0不在该环中,此时需要先经过一次交换使0元素进入该环,这时环中有n+1个元素,需要进行n次交换使元素有序,所以总共需要n+1次交换
下面是代码:
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
int main()
{
int n;
scanf("%d",&n);
int a[n];
bool circle[n];//记录元素是否已经属于环
int i;
int start;
for(i=0;i<n;i++)
{
scanf("%d",&a[i]);
if(a[i]==0)
start=i;
circle[i]=false;
}
int key=1;
int now=start;
int tatol=0;
int num=1;
circle[now]=true;
while(a[now]!=start)
{
now=a[now];
circle[now]=true;
num++;
}
tatol=num-1;
for(i=0;i<n;i++)
{
num=1;
if(circle[i]==false)
{
now=i;
circle[i]=true;
while(a[now]!=i)
{
now=a[now];
circle[now]=true;
num++;
}
}
if(num!=1)
tatol=num+1+tatol;
}
printf("%d\n",tatol);
return 0;
}