POJ 1026 Cipher(置换群)循环节

Bod 和 Alice 计划使用一种全新的编码方案,令人惊讶的是这不是一个公开的公匙密码,但是他们的编码基于密匙,在 Philadelphia on February 16th他们的会议中选择了密匙,他们选择的密匙是一个两两不等的整数序列,a1.....an,大于0并且小于等于n,编码基于一下原则。
下面的信息是关键,这样关键的人物信息和数字相对齐,一个字符在i位置,编码的时候把他放在ai,ai就是相应数字位置的关键,并且他们以同样的编码信息进行编码,这个过程重复k次,在k次以后他们交换彼此的编码。
这段信息的长度小于或者等于n,如果小于n,那么就在信息的后面能添加空格使它等于n,
写一个程序完成这个编码
本题先开始给了n个数,代表编码的方案,例如

Sample Input

10
4 5 3 7 2 8 1 6 10 9
1 Hello Bob
1995 CERC
0
0

Sample Output

BolHeol  b
C RCE
 
 
给出的
4 5 3 7 2 8 1 6 10 9
表示:
第一个位置的字符经过一次置换后会出现在第4位置, 第二位置的编号会到第五位置.....
所以可以得到所有的置换群为(1,4,7)(2,5)(3)(6,8)(9,10) 这是经过0次变换的结果。
经过k次变换只需要单独的在每个群里进行移动就行了,所以,求出置换群后进行下标取模就行了。
#include<iostream>  
#include<cstdio>
#include<algorithm>
#include<cstring>
#define LL long long
#define INF 0x3f3f3f3f
#define bug puts("************")
using namespace std;
const int N=300;
int index[N];
int vis[N];
int num[N];  ///置换群的大小
int arr[N][N];  ///记录每个置换群的内容
char s[N];
char str[N];
int main(){
    int n;
    while(~scanf("%d",&n),n){
        memset(vis,0,sizeof(vis));
        memset(num,0,sizeof(num));
        for(int i=1;i<=n;i++){
            scanf("%d",&index[i]);
        }
        int cnt=0;   ///置换群的总个数
        for(int i=1;i<=n;i++){
            if(!vis[i]){
                vis[i]=1;
                arr[cnt][num[cnt]++]=i;
                int tmp=index[i];
                while(!vis[tmp]){
                    vis[tmp]=1;
                    arr[cnt][num[cnt]++]=tmp;
                    tmp=index[tmp];
                }
                cnt++;
            }
        }
//        for(int i=0;i<cnt;i++){
//            for(int j=0;j<num[i];j++){
//                printf("%d ",arr[i][j]);
//            }
//            cout<<endl;
//        }
        int m;
        while(~scanf("%d",&m),m){
            gets(s);
            int len=strlen(s);  ///下标0处多读了一个空格。字符串下标从1开始

            for(int i=len;i<=n;i++) s[i]=' ';
            
            for(int i=0;i<cnt;i++){
                for(int j=0;j<num[i];j++){
                    str[arr[i][(j+m)%num[i]]-1]=s[arr[i][j]];
                }
            }
            str[n]='\0';
            printf("%s\n",str);
        }
        puts("");
    }
    return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值