Poj1721 Cards

第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;
}

————————————————
版权声明:本文为CSDN博主「行走少年郎」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/lianai911/article/details/39323335

  

posted @ 2020-01-02 16:02  我微笑不代表我快乐  阅读(133)  评论(0编辑  收藏  举报