题意:看图比较好理解吧。就是一个由小写字母和空格组成的N*N的矩阵,还有一个部分挖空的纸。把后者叠到前者上面,将挖空那些地方对应的字符按顺序写下来,接着将纸顺时针旋转90度,重复读。一共读4次,可以得到一句话。但根据第一次纸的方向不同,我们最多可以有4句话。然后给出一个字典,如果这句话里面所有单词都是字典里存在的,就认为这句话是对应的明文。如果有多种可能,取字典序最小的,这里的字典序最小是按照单词逐个比较的。
旋转的,手算一下可以发现这样的位置变化:
for(int i=0; i<n; i++){
for(int j=0; j<n; j++){
tmp[j][n-1-i] = mask[i][j];
}
}
然后每次读到的字符,用C++的string将他们串起来。再利用sstream将这个字符串弄到流里面去,我们再从里面取出单词,这样就可以避免一开始读到的句子里面有多余的空格以及单词数不清楚的情况。
这里要注意,输入的第一个矩阵空格是用‘.'代替的,可以在输入的时候将它们替换回空格。
解决完这两个问题,剩下的就是细心码代码了,整体还是不难的。
字典的可以用一个set保存就好了。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<string>
#include<set>
#include<sstream>
#include<vector>
using namespace std;
const int N = 100;
const int M = 3000;
int T, n, m, cnt;
char map[N][N];
char mask[N][N], tmp[N][N];
set<string> ST;
string ans;
vector<string> V, G;
char word[4][M];
void Rotate(){
for(int i=0; i<n; i++){
for(int j=0; j<n; j++){
tmp[j][n-1-i] = mask[i][j];
}
}
for(int i=0; i<n; i++){
for(int j=0; j<n; j++){
mask[i][j] = tmp[i][j];
}
}
}
void read(int x){
int len = 0;
for(int i=0; i<n; i++){
for(int j=0; j<n; j++){
if(mask[i][j]=='*'){
word[x][len++] = map[i][j];
}
}
}
word[x][len]='\0';
}
bool ok(string str){
stringstream ss(str);
G.clear();
while(ss >> str){
if(!ST.count(str)) return 0;
G.push_back(str);
}
return 1;
}
bool cmp(){
int i;
for(i=0; i<G.size() && i<V.size(); i++){
if(G[i]<V[i]) return 1;
if(G[i]>V[i]) return 0;
}
if(i==G.size()) return 1;
else return 0;
}
bool solve(){
cnt = 0;
for(int i=0; i<4; i++){
if(i) Rotate();
read(cnt);
if(strcmp(word[cnt], "")) cnt++;
}
bool flag = 0;
for(int i=0; i<4; i++){
string str = "";
for(int j=0; j<4; j++){
str += word[(i+j)%4];
}
//printf("find: %s\n", str.c_str());
if(ok(str)){
if(!flag || cmp()){
flag = 1;
ans = str;
V.resize(G.size());
for(int j=0; j<G.size(); j++) V[j] = G[j];
}
}
}
return flag;
}
int main(){
//freopen("001.txt", "r", stdin);
scanf("%d", &T);
for(int t=1; t<=T; t++){
scanf("%d", &n);
for(int i=0; i<n; i++){
scanf("%s", map[i]);
for(int j=0; j<n; j++){
if(map[i][j]=='.') map[i][j]=' ';
}
}
for(int i=0; i<n; i++) scanf("%s", mask[i]);
scanf("%d", &m);
ST.clear();
while(m--){
scanf("%s", word[0]);
ST.insert(word[0]);
}
printf("Case #%d:", t);
if(solve()){
for(int i=0; i<V.size(); i++) printf(" %s", V[i].c_str());
puts("");
}
else puts(" FAIL TO DECRYPT");
}
return 0;
}