题目:http://poj.org/problem?id=1026
题意:给你n个数字,然后给你一个字符串,按照n个数字的指示,将字符串的字母重新排序
10(10个数字)
4 5 3 7 2 8 1 6 10 9
1 Hello Bob (1表示重排一次,空格后面就是要排的字符串)
1995 CERC (1995表示重排1995次)
BolHeol b C RCE
例如: 4 5 3 7 2 8 1 6 10 9
H e l l o B o b (不够的补空格)
得到: B o l H e o l b
分析:
key:
4 5 3 7 2 8 1 6 10 9(转换为数组的下标为:3 4 2 6 1 7 0 5 9 8)
消息长度也为10,下标为
0 1 2 3 4 5 6 7 8 9
其实就是消息的下标按照key来置换,当经过若干次交换之后又会回到原来的位置,姑且称这个交换的次数为循环长度loopLen
例如:0->3->6->0,那么0号位置的消息字符的循环长度loopLen[0] = 3
1->4->1,那么1号位置的消息字符的循环长度loopLen[1] = 2
这样,我们算出每个位置的循环长度,在需要进行k次加密的时候,只需要交换该位置i上的字符k%loopLen[i]次就可以得到最终该位置上应该有的字符。
代码:
#include<iostream>
#include<cstdio>
using namespace std;
int main()
{
int path[200][200];//保存路径
int keyarr[200];//加密数字
int period[200];//保存周期
int N;//加密包含多少个秘钥
int k;//加密多少次
char src[500],ans[500];//需要加密的源字符串
for (scanf("%d",&N);N;scanf("%d",&N)){
int key;
int i,j;
memset(period,0,sizeof(int)*200);
for(i=0;i<N;i++){
scanf("%d",&key);
keyarr[i] = key -1;//因为索引是从0开始的
}
for (i=0;i<N;i++){
j=i;//搜索第i个元素的周期
path[i][0]=j;
period[i]=1;
for (j=keyarr[j];j!=i;j=keyarr[j]){
path[i][period[i]++]=j;
}
}
for (scanf("%d",&k);k;scanf("%d",&k)){
getchar();//读空缓冲区里面的内容
gets(src);
for (i=0;src[i];i++);
for (;i<N;i++)src[i]=' ';//不够的补上空格
for (i=0;i<N;i++)ans[path[i][k%period[i]]]=src[i];
ans[N]=0;
puts(ans);
}
printf("\n");
}
return 0;
}