第i个位置的牌是a[i],一次交换后第i个位置的牌变成a[a[i]]。
序列所有位置经过一次交换为一次交换,
已知交换m次之后的序列,求原先序列
思路:
给出a[i]为4 7 5 6 1 2 3
进行一次变换
1 2 3 4 5 6 7 4 7 5 6 1 2 3 1 2 3 4 5 6 7
* =
4 7 5 6 1 2 3 6 3 1 2 4 7 5 6 3 1 2 4 7 5
进行二次变换
1 2 3 4 5 6 7 6 3 1 2 4 7 5 1 2 3 4 5 6 7
* =
6 3 1 2 4 7 5 7 1 6 3 2 5 4 7 1 6 3 2 5 4
进行三次变换
1 2 3 4 5 6 7 7 1 6 3 2 5 4 1 2 3 4 5 6 7
* =
7 1 6 3 2 5 4 4 7 5 6 1 2 3 4 7 5 6 1 2 3
则进行三次变换后得到4 7 5 6 1 2 3
原序列在第三次变换的时候出现了循环
考虑一般情况。
因为原序列为1~N个不同的数,则序列能构成至少一个置换群,
则经过多次变换后肯定
会出现循环,
现在我们求出置换的循环节,已知新的序列,和进行交换的次数,
则再进行res - s % res
次交换即可得到原序列。
//res为循环节,s为给出的变换次数
#include <stdio.h>
#include <string.h>
int Array[1010],ArrayA[1010],ArrayB[1010];
void GetNext(int n)
{
for(int i = 1; i <= n; i++)
ArrayB[i] = ArrayA[ArrayA[i]];
for(int i = 1; i <= n; i++)
ArrayA[i] = ArrayB[i];
}
bool IsSame(int n)
{
for(int i = 1; i <= n; i++)
if(ArrayB[i]!=Array[i])
return false;
return true;
}
int main()
{
int n,s;
while(~scanf("%d%d",&n,&s))
{
for(int i = 1; i <= n; i++)
{
scanf("%d",&Array[i]);
ArrayA[i] = Array[i];
}
int res;
for(res = 1;;res++)
{
GetNext(n);
if(IsSame(n))
break;
}
int m = res - s % res;
int num = 0;
while(num < m)
{
GetNext(n);
num++;
}
for(int i = 1; i <= n; i++)
printf("%d\n",ArrayB[i]);
}
return 0;
}