pku1026Cipher 置换群

http://acm.pku.edu.cn/JudgeOnline/problem?id=1026

题意是:给出n个数字出现的顺序,给出一个字符串加密的次数k,再给一串字符串,长度少于n,用空格补全;按着每个字符所处位置的数字进行排序加密,我们可以发现每个数字经过x次加密就能构成一个循环,这样我们只要找到这个循环周期x,就好了,加密次数k要用到模运算来处理,这样才不会超时。

 

加密方式如题中所给:
1 2 3 4 5 6 7 8 9 10
4 5 3 7 2 8 1 6 10 9

对于第一个字符,加密3次的结果如下:

1 --> 4 --> 7 -->1

对于第二个字符,加密2次的结果如下:

2 --> 5 --> 2

可以看到,加密一定次数后,结果会构成一个循环,如果我们求出这个循环周期,那么加密的次数就可以使用取余运算进行缩减了。

#include<iostream> using namespace std; #define MAX 201 int n, T[MAX], key[MAX]; void fun() //求置换循环周期 { int i,j,count; for(i=1; i<=n; i++) { j = key[i]; count = 1; while(i != j) //直到回到自己本身,就是一个置换循环周期; { count++; j = key[j]; } T[i] = count; //第i数字的循环周期数存放在T[i]中; } } int main() { int i,j,k,len,pos; char str[MAX], ch[MAX]; while(scanf("%d",&n) != EOF) { if(n==0) break; for(i=1; i<=n; i++) scanf("%d",&key[i]); memset(T,0,sizeof(T[0])); fun(); while(scanf("%d",&k) && k) { getchar(); gets(str+1); //读入字符串,注意坐标从1开始;目的是忽略k后面的一个空格; len = strlen(str+1); /*while(len<=n) //补充空格 { str[++len] = ' '; }*/ for(i=len+1; i<=n; i++)//补充空格 str[i] = ' '; str[n+1] = '/0'; //注意; for(i=1; i<=n; i++) { pos = i; for(j=0; j<k%T[i]; j++) //k%T[i]处理后结果位置一样,模运算表明:加速,要是不%T[i],就会超时。 pos = key[pos]; //就是k%T[i]次加密后,字符i的最终位置,如1->4->7->1,这里就是7; ch[pos] = str[i]; //把字符i放到最终的位置上; //cout<<str[i]<<" "<<pos<<" "<<i<<endl; } ch[n+1] ='/0'; //千万要注意; printf("%s/n",ch+1); //puts(ch+1); } printf("/n"); } return 0; }


 

你可能感兴趣的:(加密,fun)