Вы перехватили плохо развитую террористическую ячейку, которая использует метод Цезаря в качестве шифра. Сообщения всегда на английском языке. Они заменяют каждую букву другой буквой, перемещая K-позиции алфавита. Так, например, если мы переместим алфавит на две позиции вперед, мы получим следующее соответствие:
**АБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЫЭЮЯ
CDEFGHIJKLMNOPQRSTUVWXYZAB **
Конечно, этот метод имеет очень простую атаку:
Попробуйте все возможные замены;
Рассчитайте для каждой возможной замены следующую меру между ожидаемой относительной частотой каждой буквы Ei и полученной **Oi ** по формуле: (Ei-Oi)^2 / Ei
Ваша программа должна прочитать строку текста длиной не более 10^4 символов.
Ваша программа должна вывести необходимое смещение и расшифрованный текст. Ваша программа должна обрабатывать только буквы (верхние или строчные).
Напишите программу, которая читает строку текста и расшифровывает ее. Используйте таблицу ниже для значения Ei (третий столбец) каждой буквы:
Э 11,1607% 56,88 М 3,0129% 15,36
А 8,4966% 43,31 Н 3,0034% 15,31
Р 7,5809% 38,64 Г 2,4705% 12,59
И 7,5448% 38,45 Б 2,0720% 10,56
О 7,1635% 36,51 Ж 1,8121% 9,24
Т 6,9509% 35,43 Д 1,7779% 9,06
Н 6,6544% 33,92 Вт 1,2899% 6,57
С 5,7351% 29,23 К 1,1016% 5,61
Л 5,4893% 27,98 В 1,0074% 5,13
С 4,5388% 23,13 Х 0,2902% 1,48
У 3,6308% 18,51 З 0,2722% 1,39
Д 3,3844% 17,25 Дж 0,1965% 1,00
Р 3,1671% 16,14 К 0,1962% 1,00
Примеры: ** Вход 1**
GXOXKFHKX
Выход 1
7 БОЛЬШЕ НИКОГДА
Вход 2
Oj wz, jm ijo oj wz, ocvo dn ocz lpznodji: Rczoczm 'odn ijwgzm di ocz hdiy oj npaazm.
Выход 2
5 Быть или не быть, вот в чем вопрос: благороднее ли в уме страдать.
#include <stdio.h>
#include <string.h>
double tab[26] = {43.31, 10.56, 23.13, 17.25, 56.88, 9.24,
12.59, 15.31, 38.45, 1.00, 5.61, 27.98,
15.36, 33.92, 36.51, 16.14, 1.00, 38.64,
29.23, 35.43, 18.51, 5.13, 6.57, 1.48,
9.06, 1.39};
void calcularfrequencias(const char texto[], double frequencias[])
{
int letras = 0;
for (int i = 0; texto[i] != '\0'; i++)
{
char c = texto[i];
if (c >= 'A' && c <= 'Z')
{
frequencias[c - 'A']++;
letras++;
}
else if (c >= 'a' && c <= 'z')
{
frequencias[c - 'a']++;
letras++;
}
}
for (int i = 0; i < 26; i++)
{
frequencias[i] /= letras;
}
}
int encontrardeslocamento(double frequencias[])
{
int deslocamento = 0;
double menor = 1e9;
for (int i = 0; i < 26; i++)
{
double diferenca = 0.0;
for (int j = 0; j < 26; j++)
{
int x = (j + i) % 26;
diferenca += (frequencias[j] - tab[x]) * (frequencias[j] - tab[x]);
}
if (diferenca < menor)
{
menor = diferenca;
deslocamento = i;
}
}
return deslocamento;
}
void decifrar(char texto[], int deslocamento)
{
for (int i = 0; texto[i] != '\0'; i++)
{
char c = texto[i];
if (c >= 'A' && c <= 'Z')
{
printf("%c", ((c - 'A' + deslocamento) % 26) + 'A');
}
else if (c >= 'a' && c <= 'z')
{
printf("%c", ((c - 'a' + deslocamento) % 26) + 'a');
}
else
{
printf("%c", c);
}
}
}
int main()
{
char texto_cifrado[10000];
if (fgets(texto_cifrado, sizeof(texto_cifrado), stdin) != NULL)
{
double frequencias[26];
calcularfrequencias(texto_cifrado, frequencias);
int deslocamento = encontrardeslocamento(frequencias);
printf("%d ", deslocamento);
decifrar(texto_cifrado, deslocamento);
}
return 0;
}
Я пробовал это, но когда я пробую, это не работает при одном вводе: Gx ‘Fwnwj—fwnwjegjw’».
на выходе должно быть: 8 «Никогда-никогда».
но в этом коде на выходе будет 21 Bs «Arire—arirezber». и я не могу этого понять.
Спасибо за помощь.
Есть две ошибки: (1) вы не обнуляете frequencias вначале и (2) вы забыли разделить разницу на Ei, которая есть tab[x] в вашем коде.
@Yunnosch уже решил эту проблему, я забыл добавить две вещи, спасибо!
Собираетесь ли вы теперь поделиться своим решением, добавив сообщение с ответом? Или вы в противном случае удалите этот вопрос?
@Yunnosch Думаю, я не могу добавить сообщение с ответом, поэтому собираюсь отредактировать и добавить решение
Нет. Создайте ответный пост. Не добавляйте решение к вопросу, пожалуйста. Даже добавление «SOLVED» не соответствует концепции StackOverflow. Здесь должна быть возможность создать ответный пост, иначе опишите, что вам мешает. Я постараюсь помочь вам добраться до корня этой странности.





Регулировка:
frequencias [i] = 0;
поэтому перед началом вычислений он начинается с чистого массива, без сохранения значений в frequencias [i], иначе он начинался бы с frequencias[последнее вычисленное значение];
и
diferenca += (frequencias[j] - tab[x]) * (frequencias[j] - tab[x]) / tab [x];
деление «диференсы» на ожидаемую частоту табуляции [x] (это должна быть соответствующая формула, которую они дают в задании).
#include <stdio.h>
#include <string.h>
double tab[26] = {43.31, 10.56, 23.13, 17.25, 56.88, 9.24,
12.59, 15.31, 38.45, 1.00, 5.61, 27.98,
15.36, 33.92, 36.51, 16.14, 1.00, 38.64,
29.23, 35.43, 18.51, 5.13, 6.57, 1.48,
9.06, 1.39};
void calcularfrequencias(const char texto[], double frequencias[])
{ for (int i = 0; i < 26; i++)
{
frequencias [i] = 0;
}
int letras = 0;
for (int i = 0; texto[i] != '\0'; i++)
{
char c = texto[i];
if (c >= 'A' && c <= 'Z')
{
frequencias[c - 'A']++;
letras++;
}
else if (c >= 'a' && c <= 'z')
{
frequencias[c - 'a']++;
letras++;
}
}
for (int i = 0; i < 26; i++)
{
frequencias[i] /= letras;
}
}
int encontrardeslocamento(double frequencias[])
{
int deslocamento = 0;
double menor = 1e9;
for (int i = 0; i < 26; i++)
{
double diferenca = 0.0;
for (int j = 0; j < 26; j++)
{
int x = (j + i) % 26;
diferenca += (frequencias[j] - tab[x]) * (frequencias[j] - tab[x]) / tab [x];
}
if (diferenca < menor)
{
menor = diferenca;
deslocamento = i;
}
}
return deslocamento;
}
void decifrar(char texto[], int deslocamento)
{
for (int i = 0; texto[i] != '\0'; i++)
{
char c = texto[i];
if (c >= 'A' && c <= 'Z')
{
printf("%c", ((c - 'A' + deslocamento) % 26) + 'A');
}
else if (c >= 'a' && c <= 'z')
{
printf("%c", ((c - 'a' + deslocamento) % 26) + 'a');
}
else
{
printf("%c", c);
}
}
}
int main()
{
char texto_cifrado[10000];
if (fgets(texto_cifrado, sizeof(texto_cifrado), stdin) != NULL)
{
double frequencias[26];
calcularfrequencias(texto_cifrado, frequencias);
int deslocamento = encontrardeslocamento(frequencias);
printf("%d ", deslocamento);
decifrar(texto_cifrado, deslocamento);
}
return 0;
}
Предполагая, что вы превращаете комментарий в ответ, скажите об этом. (Автор комментария решил не отвечать, так что это нормально. И, возможно, это только мое мнение, что вам все же следует упомянуть об этом. Просто рекомендация.)
@Yunnosch там написано, что я смогу принять свой ответ только через два дня
Помощь по форматированию публикации можно найти здесь: stackoverflow.com/help/formatting .
Да, вы не можете принять собственный ответ в течение определенного времени. Это правда. У вас есть вопросы относительно этого правила?
Какие частоты ваша программа определяет для правильного 8 и неправильного 21? Имеет ли смысл, если ваша программа выбирает 21, судя по этим числам? Я спрашиваю, потому что это разделяет две основные возможные ошибки: а) ошибка в измерении частот, б) принятие решения на основе этих данных.