[ACM]暗算 2.0

18 篇文章 0 订阅
13 篇文章 0 订阅

背景

此“暗算”非彼《暗算》 眨眼 ,虽然我们没有电影中阿柄惊人的听力,可以辨别破译密码,但是我们也可以成为破译专家。

现在就来给大家作一个集训:

改变阿拉伯字母的顺序是文本加密中十分常用的方法,但是并不安全。也就是说,把文本中的每一个阿拉伯字母都要一致地替换成一些其他的字母。为了保证加密的可逆性,需要每个阿拉伯字母都有唯一一个替换的字母(也就说,任意两个阿拉伯字母都不可以用同一个字母来替换)。

最有效的密码分析方法就是“已知明文攻击(known-plaintext attack)”法。在此种方法中,密钥专家掌握着敌方加密的短语或语句,然后通过观察这些加密文字从而推导出译码的方法。

你现在的任务就是来破译几行加密的文本,这些文本是用一条密钥加密的,即某一行加密前就是密钥本身。密钥是一个包含了全部 26 个英文字母的字符串,譬如在“暗算 1.0”中,使用的密钥是:

the quick brown fox jumps over the lazy dog

不过一个固定的密钥实在是太容易破译了,只要掌握了规律,就不太费劲。为了能够保证信息的安全性,我们决定在此次集训中,使用可变化的密钥。也就是说,每一组测试用例,都包含着自己的密钥。

输入

首先是单独一个正整数用来说明测试的组数,后边跟着一行字符串,这行字符串就是这次测试用例所使用的密钥。再接着是一个空白行。而且,连续两组测试之间也有一个空白行。

每组测试有多行输入组成。加密的方式如上所示。加密的文本行只包含有小写字母和空格,而且长度不超过 80 个字符。最多有 100 条输入的文本行。

输出

对应每组测试, 解密每一行的信息,并且把标准输出打印出来。如果有多于一种的解密方法,那么任何一种都可以。如果没有解密的方法,则输出信息“No solution.”

每两组测试输出之间必须用一个空白行分隔开。

来源

http://online-judge.uva.es/p/v8/850.html


例如:

输入:

  1. 1↵
  2. the quick brown fox jumps over the lazy dog↵
  3. vtz ud xnm xugm itr pyy jttk gmv xt otgm xt xnm puk ti xnm fprxq↵
  4. xnm ceuob lrtzv ita hegfd tsmr xnm ypwq ktj↵
  5. frtjrpgguvj otvxmdxd prm iev prmvx xnmq↵
输出:

  1. now is the time for all good men to come to the aid of the party↵
  2. the quick brown fox jumps over the lazy dog↵
  3. programming contests are fun arent they↵


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

char ciphers[100][100];
char keys[100];

void Translate(char *pwd)//解密
{
	int i = 0,j = 0;
	for (i = 0; ciphers[i][0] ; i++)
	{
		for (j = 0; ciphers[i][j] != '\0'; j++)
		{
			if (ciphers[i][j] >= 'a' && ciphers[i][j] <= 'z')
				printf("%c", pwd[ciphers[i][j] - 97]);
			else
				printf("%c", ciphers[i][j]);
		}
		printf("\n");
	}
}

void CreateIndex(char *pwd, char *key)//建立密码索引
{
	for	(int i = 0; i < 100; i++)
	{
		if (key[i] >= 'a' && key[i] <= 'z')
			if (pwd[key[i] - 97] == '\0')
				pwd[key[i] - 97] = keys[i];
	}
}

int IsKey(char *cipher)//判断是否为密钥
{
	if (strlen(cipher) != strlen(keys))
		return 0;
	char p[100];
	int i,j;
	for (i = 0; cipher[i] != '\0'; i++)
	{
		for (j = 0; j < i; j++)
		{
			if (cipher[j] == cipher[i])
			{
				p[i] = p[j];
				break;
			}
		}
		if (j == i)
			p[i] = keys[i];
	}
	p[i] = '\0';

	if (strcmp(p,keys) == 0)
		return 1;
	return 0;
}

int main()
{
	freopen("in.txt", "r", stdin);
	char cipher[100], *key,	pwd[26],blank[10];
	int n;
	scanf("%d", &n);
	gets(blank);
	while (n--)
	{
		memset(ciphers,'\0',10000);
		memset(pwd, '\0', 26);
		memset(keys, '\0', 100);
		int i = 0;
		gets(keys);//读入密钥
		gets(blank);
		while (gets(cipher) && strlen(cipher) > 0)
		{
			//对读入的密文判断是否是密钥的密文
			strcpy(ciphers[i++], cipher);
			if (IsKey(cipher))
			{
				key = cipher;
				//对密钥中的字符建立索引,下标为ascll值
				memset(pwd,0,26);
				CreateIndex(pwd, key);
			}
		}
		Translate(pwd);
	}
	return 0;
}


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值