F(1863): Square Cipher

Description

    In Dorothy Sayers' novel "Have His Carcass", Lord Peter Wimsey describes a cryptography technique that is simple for encoding and decoding, yet relatively hard to crack. Your job is to implement this technique.
    Here's how it works, in Sayers' (edited) words:
    You choose a key-word of six letters or more, none of which recurs. Such as, for example, SQUANDER. Then you make a diagram of five squares each way and write the key-word in the squares like this:

      +-----+-----+-----+-----+-----+
      |     |     |     |     |     |
      |  S  |  Q  |  U  |  A  |  N  |
      |     |     |     |     |     |
      +-----+-----+-----+-----+-----+
      |     |     |     |     |     |
      |  D  |  E  |  R  |     |     |
      |     |     |     |     |     |
      +-----+-----+-----+-----+-----+
      |     |     |     |     |     |
      |     |     |     |     |     |
      |     |     |     |     |     |
      +-----+-----+-----+-----+-----+
      |     |     |     |     |     |
      |     |     |     |     |     |
      |     |     |     |     |     |
      +-----+-----+-----+-----+-----+
      |     |     |     |     |     |
      |     |     |     |     |     |
      |     |     |     |     |     |
      +-----+-----+-----+-----+-----+

    Then you fill up the remaining spaces with the rest of the alphabet in order, leaving out the ones you've already got.
    You can't put twenty-six letters in twenty-five spaces, so you pretend you're an ancient Roman or a medieval monk and treat I and J as one letter. So you get this:

      +-----+-----+-----+-----+-----+
      |     |     |     |     |     |
      |  S  |  Q  |  U  |  A  |  N  |
      |     |     |     |     |     |
      +-----+-----+-----+-----+-----+
      |     |     |     |     |     |
      |  D  |  E  |  R  |  B  |  C  |
      |     |     |     |     |     |
      +-----+-----+-----+-----+-----+
      |     |     |     |     |     |
      |  F  |  G  |  H  |  IJ |  K  |
      |     |     |     |     |     |
      +-----+-----+-----+-----+-----+
      |     |     |     |     |     |
      |  L  |  M  |  O  |  P  |  T  |
      |     |     |     |     |     |
      +-----+-----+-----+-----+-----+
      |     |     |     |     |     |
      |  V  |  W  |  X  |  Y  |  Z  |
      |     |     |     |     |     |
      +-----+-----+-----+-----+-----+

    Now let's take a message -- What shall we say? 'All is known, fly at once' -- that classic hardy perennial. We write it down all of a piece and break it into groups of two letters, reading from left to right. It won't do to have two of the same letters coming together in a pair, so where that happens, we shove in a Q, which won't confuse the reader. Now our message runs:

AL QL IS KN OW NF LY AT ON CE

    If there is an odd letter at the end, we'd add on another Q to square it up. Now we take our first group, AL. We see that they come at the corners of a rectangle in which the other corners are SP. So we put down SP for the first two letters of the coded message. In the same way, QL becomes SM and IS becomes FA.
    Ah, but here's KN. They both come on the same vertical line. In this case you take the letter next below each -- TC. Next comes OW, which translates to MX. Going on, SK, PV, NP, TU... If your first diagonal went from bottom to top, you must take it the same way again. ON = TU, NO would be UT.
    CE come on the same horizontal line. In that case, you take the letter to the right of each. Since there isn't a letter to the right of C, you start again at the beginning of the line, producing DR.. Your coded message stands now:

SP SM FA TC MX SK PV NP TU DR

    To make it look pretty and not give the method away, you can break it up into any lengths you like, or you can embellish it with punctuation as haphazard:

S.P. SMFA. TCMXS, KPVM, PT! UDR.

    It's very ingenious. You can't guess it by way of the most frequent letter, because you get a different letter for each time, according as it's grouped to the next letter. And you can't guess individual words, because you don't know where the words begin and end. Is it at all possible to decode it without the key-word?
    "Oh dear, yes," said Wimsey. "Any code ever coded can be decoded with pains and patience..."

Input

    The input for your program will be a series of keywords and messages to encode, alternating line-by-line, until the end-of-file flag of 999. Using the above technique, you are to encode the message, using the word.
    Input will be in upper case and will contain no punctuation. Unlike Sayers’ example, letters may occur more than once in the key-words, in which case you must ignore all but the first occurrence of the letter.

Output

    Print each message, encrypted, using two letter groups and no punctuation, separated by a single white space. Separate each message by one blank line.
    Print an I for IJ.

Sample Input

SQUANDER
ALL IS KNOWN FLY AT ONCE
999

Sample Output

SP SM FA TC MX SK PV NP TU DR

Hint

    Notes:
    If the last letter is both odd and repeated, treat it as repeated and put the 'Q' before it, not afterward. That is, ALL becomes ALQL for encoding purposes.
    In the unlikely case of two Qs in a row, insert a Z between them. Also, augment odd-length messages ending with a Q by using a Z. Thus, FAQQAD becomes FAQZQADQ and HUQ becomes HUQZ for encoding.

题意:1.密码表(IJ看成一个字母)    
利用第一个字符串给的字母按字母出现的顺序填5*5的矩阵,之后再将未出现的字母按字母表顺序填在矩阵中 
2. It won't do to have two of the same letters coming together in a pair, so where that happens, we shove in a Q, which won't confuse the reader.
出现重复的字母,在中间加Q  
two Qs in a row, insert a Z between them.
有Q则改成Z 
3.If there is an odd letter at the end, we'd add on another Q to square it up.
末尾单出一个字母的,加Q补全 
4. AL. We see that they come at the corners of a rectangle in which the other corners are SP.
将字母换成字母为对顶点的矩形的另外两个对顶点(eg.(x1,y1)(x2,y2)->(x1,y2)(x2,y1)) 
They both come on the same vertical line. In this case you take the letter next below each
同列的字母下移一位
come on the same horizontal line. In that case, you take the letter to the right of each
同行的字母右移一位  
Print an I for IJ.

ps:代码是对着题解写的大哭

#include<iostream>
#include<string>
using namespace std;
struct point{
	int x,y;
	point(int xx=0,int yy=0){
		x=xx,y=yy;
	}
}p[30];
char mat[5][5];
void change(point &u,point &v,point a,point b){
	if(a.x==b.x) {u=point(a.x,(a.y+1)%5),v=point(b.x,(b.y+1)%5);}
	else if(a.y==b.y) {u=point((a.x+1)%5,a.y),v=point((b.x+1)%5,b.y);}
	else{u=point(a.x,b.y),v=point(b.x,a.y);}
}
int main(){
	while(1){
		string s1,s2,s3;
		getline(cin,s1);
		if(s1=="999") break;
		getline(cin,s2);
		//if(s2[s2.length()-1]=='\r') s2.resize(s2.length()-1);
		int len3,len1=s1.length(),len2=s2.length();
		for(int i=0;i<len1;i++) if(s1[i]=='J') s1[i]='I';
		for(int i=0;i<len2;i++) if(s2[i]=='J') s2[i]='I';
		int pos=0,c=-1,vis[30]={0};
		for(int i=0;i<5;i++)
		for(int j=0;j<5;j++){
			if(pos<len1){
				mat[i][j]=s1[pos],vis[s1[pos]-'A']=1;
				while(++pos<len1) if(vis[s1[pos]-'A']==0) break;
			}
			else{
				while(vis[c+1=='J'-'A'?c+=2:c+=1]);
				mat[i][j]='A'+c,vis[c]=1;
			}
			p[mat[i][j]-'A']=point(i,j);
		}
		bool flag=1;s3="";
		for(int i=0;i<len2;i++)
		if(s2[i]>='A'&&s2[i]<='Z'){
			if(flag){
				s3+=s2[i];flag=0;
				continue;
			}
			if(s2[i]==s3[s3.length()-1]) s3+=(s2[i]=='Q'?'Z':'Q');
			s3+=s2[i];
		}
		if(s3.length()%2) s3+=(s3[s3.length()-1]=='Q'?'Z':'Q');
		//len3=s3.length();不能用 
		for(int i=0;i<s3.length();i++)
		if(i%2){
			point u,v;
			change(u,v,p[s3[i-1]-'A'],p[s3[i]-'A']);
			cout<<mat[u.x][u.y]<<mat[v.x][v.y];
			if(i+1==s3.length()) cout<<endl;
			else          cout<<" ";
		}
	}
}



     
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值