您的位置:首页 > 其它

ZOJ 1009

2015-04-07 16:23 330 查看
解码的题目,首先你要弄明白转子旋转怎么模拟!

旋转一次之后,每个字母对应的节点转了一位,与此同时,每个节点对应的密文也旋转了一次,如果听不明白就自己好好研究以下的三幅图!



三个转子的关系就像秒针,分针,时针一样!

然后模拟就行了,我是用数字处理的,把字母都转换成数字处理,最后再转回来。

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

int m,n;
int rotors[3][30];

void revolve(int list[][30],int cnt[]);
void revolve_rotor(int *str);
char decode(int list[][30],char c);

int main()
{
int num = 0;
scanf("%d",&m);
getchar();
while(m!=0)
{
int i,j;
for(i = 0;i < 3;i++)
{
for(j = 0;j < m;j++)
{
rotors[i][j] = getchar() - 'A';
}
getchar();
}
scanf("%d",&n);
getchar();
num++;
if(num>1)
{
printf("\n");
}
printf("Enigma %d:\n",num);

for(i = 0;i < n;i++)
{
char result[1400];
char str[1400];
int cnt[2] = {0},count = 0;
int list[3][30];
int a,b;
int len;
for(a = 0;a < 3;a++)
{
for(b = 0;b < m;b++)
{
list[a][b] = rotors[a][b];
}
}
gets(str);
len = strlen(str);
for(a = 0;a < len;a++)
{
char c;
c = decode(list,str[a]);
revolve(list,cnt);
result[count++] = c;
}
result[count] = '\0';
puts(result);
}

scanf("%d",&m);
getchar();
}
return 0;
}

void revolve(int list[][30],int cnt[])
{
revolve_rotor(list[0]);
cnt[0]++;
if(cnt[0]%m==0)
{
revolve_rotor(list[1]);
cnt[1]++;
if(cnt[1]%m==0)
{
revolve_rotor(list[2]);
}
}
}

void revolve_rotor(int *str)
{
int i;
int t = str[m - 1];
for(i = m-1;i > 0;i--)
{
str[i] = (str[i-1] + 1)%m;
}
str[0] = (t+1)%m;
}

char decode(int list[][30],char c)
{
char t;
int i,now;
now = c - 'A';
for(i = 0;i < m;i++)
{
if(list[2][i]==now)
{
now = i;
break;
}
}
for(i = 0;i < m;i++)
{
if(list[1][i]==now)
{
now = i;
break;
}
}
for(i = 0;i < m;i++)
{
if(list[0][i]==now)
{
now = i;
break;
}
}
t = now + 'a';
return t;
}


AC后搜了一下其他人的思路,发现有人使用偏移量来做的,就是把转子的加密作用等效成对于明文字母的偏移,比如明文为‘a’,密文为‘B’,偏移量就是1.把每个转子的偏移量用数组存储,然后每次旋转就是把旋转的转子的偏移量数组循环向右移动一位。这样解密的时候,只要减去偏移量可以的出明文。我是纯模拟,他的这种思路简单地多。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: