题目描述:给定一个n*n的messag图,由字母和空格组成,用一个n*n有n*n/4个洞的mask盖在messa上面,通过洞自上至下,从左到右读取洞中露出的字母或空格,然后将mask顺时针旋转九十度继续读取,直到转了360度,这4次读取的信息可以组成若干单词(单词间通过空格间隔),若出现的所有单词都在给定的单词之内,则为有效情况。由于第一次将空洞摆放时的方式不同,故可能有多种读取结果。若有若干结果符合要求,则输出字典序最小的一组。
思路:直接模拟即可。不过要注意不仅要处理前后多余的空格,单词与单词之间的空格也要处理,单词间只能由一个空格间隔,多余空格要舍弃。忘记处理中间空格是我一直PE的原因。
代码如下:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#include<cstdlib>
#include<sstream>
#include<deque>
#include<stack>
#include<set>
#include<map>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const double eps = 1e-6;
const int maxn = 50 + 20;
const int mod = 10000007;
const int dx[] = {1, -1, 0, 0, -1, -1, 1, 1};
const int dy[] = {0, 0, -1, 1, -1, 1, -1, 1};
const int Dis[] = {-1, 1, -5, 5};
const double inf = 0x3f3f3f3f;
int n, m;
char message[maxn][maxn];
char a[maxn][maxn], b[maxn][maxn], c[maxn][maxn], d[maxn][maxn];
map<string, int> mp;
vector<string> ans;
void get_mask(char x[maxn][maxn], char y[maxn][maxn]){//旋转给定的mask图,得到一开始摆放时mask所有的情况。
for(int i = 0; i < n; ++i){
for(int j = 0; j < n; ++j){
y[i][j] = x[n - 1 - j][i];
}
}
}
string get_cover(char x[maxn][maxn]){//读取mask挡住message后露出的信息。
string cnt = "";
for(int i = 0; i < n; ++i){
for(int j = 0; j < n; ++j){
if(x[i][j] == '*'){//洞
if(message[i][j] == '.'){//空格
cnt += ' ';
}
else{//小写字母
cnt += message[i][j];
}
}
// cout << "cnt==" << cnt << endl;
}
}
// cout << "cnt******" << cnt << endl;
return cnt;
}
void solve(string s1){//读取单词并判断是否符合要求。
int cur1, cur2;
bool ok, judge;
string tmp;
cur1 = 0; ok = false;judge = true;
int len = s1.size();
for(int i = 0; i < len; ++i){
if(!ok){
while(s1[cur1] == ' ' && cur1 < len) ++cur1;
if(cur1 >= len) break;
ok = true;
cur2 = cur1;
}
if(ok){
while(s1[cur2] != ' ' && cur2 < len) ++cur2;
tmp = s1.substr(cur1, cur2 - cur1);
// cout << "cur1==" << cur1 << " cur2==" << cur2 << " tmp==" << tmp << endl;
if(!mp.count(tmp)){//读取到的单词不在给定单词中,直接退出。
judge = false; break;
}
else{
cur1 = cur2;
}
ok = false;
}
}
if(judge){//所有单词均符合要求
cur1 = 0, cur2 = len - 1;
while(s1[cur1] == ' ' && cur1 < len) ++cur1;//处理最前面的多余空格
while(s1[cur2] == ' ' && cur2 >= 0) --cur2;//处理最后面的多余空格。
if(cur1 > cur2 || (cur1 == cur2 && s1[cur1] == ' ')) return;
tmp = s1.substr(cur1, cur2 - cur1 + 1);
// cout << "s1+++" << s1 << " tmp+++" << tmp << "***" << endl;
ans.push_back(tmp);
}
}
int main(){
// freopen("in.txt","r", stdin);
// freopen("out.txt","w", stdout);
int t;
int kase = 0;
scanf("%d", &t);
while(t--){
mp.clear(); ans.clear();
scanf("%d", &n);
for(int i = 0; i < n; ++i) scanf("%s", message + i);
for(int i = 0; i < n; ++i) scanf("%s", a + i);//初始mask图
scanf("%d", &m);
string word;
for(int i = 1; i <= m; ++i){
cin >> word;//给定单词
mp[word] = i;
}
get_mask(a, b);
get_mask(b, c);
get_mask(c, d);
//abcd ---- " good morning "//共四种情况,一一模拟出来即可。
string s1 = "";
s1 += get_cover(a);
s1 += get_cover(b);
s1 += get_cover(c);
s1 += get_cover(d);
// cout << "s1==" << s1 << "**" << endl;
solve(s1);
//bcda ---- "od morning go"
s1 = "";
s1 += get_cover(b);
s1 += get_cover(c);
s1 += get_cover(d);
s1 += get_cover(a);
// cout << "s1==" << s1 << "**" << endl;
solve(s1);
//cdab ---- "orning good m"
s1 = "";
s1 += get_cover(c);
s1 += get_cover(d);
s1 += get_cover(a);
s1 += get_cover(b);
// cout << "s1==" << s1 << "**" << endl;
solve(s1);
//dabc ---- "ng good morni"
s1 = "";
s1 += get_cover(d);
s1 += get_cover(a);
s1 += get_cover(b);
s1 += get_cover(c);
// cout << "s1==" << s1 << "**" << endl;
solve(s1);
printf("Case #%d: ", ++kase);
if(ans.empty()){//无解
printf("FAIL TO DECRYPT\n"); continue;
}
else{
sort(ans.begin(), ans.end());//处理中间空格,即两个单词间只能有一个空格分割它们。
string answer = "", tmp;
stringstream ss(ans[0]);
bool ok = false;
while(ss >> tmp){
if(ok) answer += " ";
else ok = true;
answer += tmp;
}
// cout << "**";
cout << answer << endl;
// cout << "**" << endl;
}
}
return 0;
}
/*
3
4
..lf
eoyv
oeou
vrer
..*.
.*..
....
*.*.
5
i
you
the
love
forever
4
.sle
s.c.
e.fs
..uu
*...
.*..
...*
..*.
1
successful
4
o.do
.ng.
grmn
o.i.
.*..
*.*.
....
*...
2
good
morning
*/